@@ -105,35 +105,73 @@ functions, which are stored in the object. Try it, it's fun!
105105
106106class Expression
107107{
108-
109108 public $ suppress_errors = false ;
110109 public $ last_error ;
111110
112- public $ v = array ('e ' => 2.71 , 'pi ' => 3.14 ); // variables (and constants)
113- public $ f = array (); // user-defined functions
114- public $ vb = array ('e ' , 'pi ' ); // constants
115- public $ fb = array ( // built-in functions
111+ /**
112+ * Function defined outside of Expression as closures
113+ *
114+ * Example:
115+ * ```php
116+ * $expr = new Expression();
117+ * $expr->functions = [
118+ * 'foo' => function ($a, $b) {
119+ * return $a + $b;
120+ * }
121+ * ];
122+ * $expr->e('2 * foo(3, 4)'); //return: 14
123+ * ```
124+ *
125+ * @var array
126+ */
127+ public $ functions = [];
128+
129+ /**
130+ * Variables (and constants)
131+ * @var array
132+ */
133+ public $ v = ['e ' => 2.71 , 'pi ' => 3.14 ];
134+
135+ private $ f = []; // user-defined functions
136+ private $ vb = ['e ' , 'pi ' ]; // constants
137+ private $ fb = [ // built-in functions
116138 'sin ' , 'sinh ' , 'arcsin ' , 'asin ' , 'arcsinh ' , 'asinh ' ,
117139 'cos ' , 'cosh ' , 'arccos ' , 'acos ' , 'arccosh ' , 'acosh ' ,
118140 'tan ' , 'tanh ' , 'arctan ' , 'atan ' , 'arctanh ' , 'atanh ' ,
119- 'sqrt ' , 'abs ' , 'ln ' , 'log ' ) ;
141+ 'sqrt ' , 'abs ' , 'ln ' , 'log ' ] ;
120142
121- public $ functions = array (); // function defined outside of Expression as closures
143+ private $ _functions = [];
122144
123145 public function __construct ()
124146 {
125147 // make the variables a little more accurate
126148 $ this ->v ['pi ' ] = M_PI ;
127149 $ this ->v ['e ' ] = exp (1 );
150+ $ this ->_functions = [
151+ 'if ' => function ($ condition , $ valueIfTrue , $ valueIfFalse ) {
152+ return $ condition ? $ valueIfTrue : $ valueIfFalse ;
153+ }
154+ ];
128155 }
129156
157+ /**
158+ * @param string $expr
159+ * @return bool|mixed|null
160+ * @throws ReflectionException
161+ */
130162 public function e ($ expr )
131163 {
132164 return $ this ->evaluate ($ expr );
133165 }
134166
167+ /**
168+ * @param string $expr
169+ * @return bool|mixed|null
170+ * @throws ReflectionException
171+ */
135172 public function evaluate ($ expr )
136173 {
174+ $ this ->_functions = array_merge ($ this ->_functions , $ this ->functions );
137175 $ this ->last_error = null ;
138176 $ expr = preg_replace ("/ \r| \n/ " , '' , trim ($ expr ));
139177 if ($ expr && $ expr [strlen ($ expr ) - 1 ] === '; ' ) {
@@ -157,7 +195,7 @@ public function evaluate($expr)
157195 return $ this ->trigger ("cannot redefine built-in function ' $ matches [1 ]()' " );
158196 }
159197
160- $ args = array () ;
198+ $ args = [] ;
161199 if ($ matches [2 ] !== '' ) {
162200 $ args = explode (', ' , preg_replace ("/\s+/ " , '' , $ matches [2 ])); // get the arguments
163201 }
@@ -174,23 +212,29 @@ public function evaluate($expr)
174212 }
175213 }
176214 }
177- $ this ->f [$ fnn ] = array ( 'args ' => $ args , 'func ' => $ stack) ;
215+ $ this ->f [$ fnn ] = [ 'args ' => $ args , 'func ' => $ stack] ;
178216 return true ;
179217 //===============
180218 }
181219 return $ this ->pfx ($ this ->nfx ($ expr )); // straight up evaluation, woo
182220 }
183221
222+ /**
223+ * @return array
224+ */
184225 public function vars ()
185226 {
186227 $ output = $ this ->v ;
187228 unset($ output ['pi ' ], $ output ['e ' ]);
188229 return $ output ;
189230 }
190231
232+ /**
233+ * @return array
234+ */
191235 public function funcs ()
192236 {
193- $ output = array () ;
237+ $ output = [] ;
194238 foreach ($ this ->f as $ fnn => $ dat ) {
195239 $ output [] = $ fnn . '( ' . implode (', ' , $ dat ['args ' ]) . ') ' ;
196240 }
@@ -203,20 +247,21 @@ public function funcs()
203247 * Convert infix to postfix notation
204248 * @param string $expr
205249 * @return array|bool
250+ * @throws ReflectionException
206251 */
207- public function nfx ($ expr )
252+ private function nfx ($ expr )
208253 {
209254 $ index = 0 ;
210255 $ stack = new ExpressionStack ;
211- $ output = array () ; // postfix form of expression, to be passed to pfx()
256+ $ output = [] ; // postfix form of expression, to be passed to pfx()
212257 $ expr = trim ($ expr );
213258
214- $ ops = array ( '+ ' , '- ' , '* ' , '/ ' , '^ ' , '_ ' , '% ' , '> ' , '< ' , '>= ' , '<= ' , '== ' , '!= ' , '=~ ' , '&& ' , '|| ' , '! ' ) ;
215- $ ops_r = array ( '+ ' => 0 , '- ' => 0 , '* ' => 0 , '/ ' => 0 , '% ' => 0 , '^ ' => 1 , '> ' => 0 ,
259+ $ ops = [ '+ ' , '- ' , '* ' , '/ ' , '^ ' , '_ ' , '% ' , '> ' , '< ' , '>= ' , '<= ' , '== ' , '!= ' , '=~ ' , '&& ' , '|| ' , '! ' ] ;
260+ $ ops_r = [ '+ ' => 0 , '- ' => 0 , '* ' => 0 , '/ ' => 0 , '% ' => 0 , '^ ' => 1 , '> ' => 0 ,
216261 '< ' => 0 , '>= ' => 0 , '<= ' => 0 , '== ' => 0 , '!= ' => 0 , '=~ ' => 0 ,
217- '&& ' => 0 , '|| ' => 0 , '! ' => 0 ) ; // right-associative operator?
218- $ ops_p = array ( '+ ' => 3 , '- ' => 3 , '* ' => 4 , '/ ' => 4 , '_ ' => 4 , '% ' => 4 , '^ ' => 5 , '> ' => 2 , '< ' => 2 ,
219- '>= ' => 2 , '<= ' => 2 , '== ' => 2 , '!= ' => 2 , '=~ ' => 2 , '&& ' => 1 , '|| ' => 1 , '! ' => 5 ) ; // operator precedence
262+ '&& ' => 0 , '|| ' => 0 , '! ' => 0 ] ; // right-associative operator?
263+ $ ops_p = [ '+ ' => 3 , '- ' => 3 , '* ' => 4 , '/ ' => 4 , '_ ' => 4 , '% ' => 4 , '^ ' => 5 , '> ' => 2 , '< ' => 2 ,
264+ '>= ' => 2 , '<= ' => 2 , '== ' => 2 , '!= ' => 2 , '=~ ' => 2 , '&& ' => 1 , '|| ' => 1 , '! ' => 5 ] ; // operator precedence
220265
221266 $ expecting_op = false ; // we use this in syntax-checking the expression
222267 // and determining when a - is a negation
@@ -308,8 +353,8 @@ public function nfx($expr)
308353 if ($ arg_count !== count ($ this ->f [$ fnn ]['args ' ])) {
309354 return $ this ->trigger ("wrong number of arguments ( $ arg_count given, " . count ($ this ->f [$ fnn ]['args ' ]) . ' expected) ' . json_encode ($ this ->f [$ fnn ]['args ' ]));
310355 }
311- } elseif (array_key_exists ($ fnn , $ this ->functions )) {
312- $ func_reflection = new ReflectionFunction ($ this ->functions [$ fnn ]);
356+ } elseif (array_key_exists ($ fnn , $ this ->_functions )) {
357+ $ func_reflection = new ReflectionFunction ($ this ->_functions [$ fnn ]);
313358 $ count = $ func_reflection ->getNumberOfParameters ();
314359 if ($ arg_count !== $ count ) {
315360 return $ this ->trigger ("wrong number of arguments ( $ arg_count given, " . $ count . ' expected) ' );
@@ -355,7 +400,7 @@ public function nfx($expr)
355400 } elseif (preg_match ("/^([a-z]\w*)\($/ " , $ val , $ matches )) { // may be func, or variable w/ implicit multiplication against parentheses...
356401 if (in_array ($ matches [1 ], $ this ->fb , true ) ||
357402 array_key_exists ($ matches [1 ], $ this ->f ) ||
358- array_key_exists ($ matches [1 ], $ this ->functions )
403+ array_key_exists ($ matches [1 ], $ this ->_functions )
359404 ) { // it's a func
360405 if ($ begin_argument && !$ stack ->incrementArgument ()) {
361406 $ this ->trigger ("unexpected '(' " );
@@ -411,16 +456,17 @@ public function nfx($expr)
411456 * @param array|bool $tokens
412457 * @param array $vars
413458 * @return bool|mixed|null
459+ * @throws ReflectionException
414460 */
415- public function pfx ($ tokens , array $ vars = array () )
461+ private function pfx ($ tokens , array $ vars = [] )
416462 {
417463 if ($ tokens === false ) {
418464 return false ;
419465 }
420466 $ stack = new ExpressionStack ();
421467 foreach ((array )$ tokens as $ token ) { // nice and easy
422468 // if the token is a binary operator, pop two values off the stack, do the operation, and push the result back on
423- if (in_array ($ token , array ( '+ ' , '- ' , '* ' , '/ ' , '^ ' , '< ' , '> ' , '<= ' , '>= ' , '== ' , '&& ' , '|| ' , '!= ' , '=~ ' , '% ' ) , true )) {
469+ if (in_array ($ token , [ '+ ' , '- ' , '* ' , '/ ' , '^ ' , '< ' , '> ' , '<= ' , '>= ' , '== ' , '&& ' , '|| ' , '!= ' , '=~ ' , '% ' ] , true )) {
424470 $ op2 = $ stack ->pop ();
425471 $ op1 = $ stack ->pop ();
426472 switch ($ token ) {
@@ -530,8 +576,8 @@ public function pfx($tokens, array $vars = array())
530576 $ args [$ this ->f [$ fnn ]['args ' ][$ i ]] = $ stack ->pop ();
531577 }
532578 $ stack ->push ($ this ->pfx ($ this ->f [$ fnn ]['func ' ], $ args )); // yay... recursion!!!!
533- } else if (array_key_exists ($ fnn , $ this ->functions )) {
534- $ reflection = new ReflectionFunction ($ this ->functions [$ fnn ]);
579+ } else if (array_key_exists ($ fnn , $ this ->_functions )) {
580+ $ reflection = new ReflectionFunction ($ this ->_functions [$ fnn ]);
535581 $ count = $ reflection ->getNumberOfParameters ();
536582 $ args = [];
537583 for ($ i = $ count - 1 ; $ i >= 0 ; $ i --) {
@@ -565,8 +611,8 @@ public function pfx($tokens, array $vars = array())
565611 $ stack ->push (0 + $ token );
566612 } else if (preg_match ("/^[' \\\"](.*)[' \\\"]$/ " , $ token )) {
567613 $ stack ->push (json_decode (preg_replace_callback ("/^[' \\\"](.*)[' \\\"]$/ " , function ($ matches ) {
568- $ m = array ( "/ \\\\'/ " , '/(?<! \\\\)"/ ' ) ;
569- $ r = array ( "' " , '\\" ' ) ;
614+ $ m = [ "/ \\\\'/ " , '/(?<! \\\\)"/ ' ] ;
615+ $ r = [ "' " , '\\" ' ] ;
570616 return '" ' . preg_replace ($ m , $ r , $ matches [1 ]) . '" ' ;
571617 }, $ token )));
572618 } elseif (array_key_exists ($ token , $ this ->v )) {
@@ -590,7 +636,7 @@ public function pfx($tokens, array $vars = array())
590636 * @param string $msg
591637 * @return bool
592638 */
593- public function trigger ($ msg )
639+ private function trigger ($ msg )
594640 {
595641 $ this ->last_error = $ msg ;
596642 if (!$ this ->suppress_errors ) {
@@ -605,7 +651,7 @@ public function trigger($msg)
605651 */
606652class ExpressionStack
607653{
608- public $ stack = array () ;
654+ public $ stack = [] ;
609655 public $ count = 0 ;
610656
611657 public function push ($ val )
0 commit comments