All the Dynamic Syntax in PHP

With PHP, dynamic calls happens when the call gets at least one of its expression’s elements (and sometimes, even all of them) at execution time. They are not known at coding time, so there are usually some variables involved in the matter. Here is a review of how to do this for all dynamic syntax in PHP.

In fact, there are very little expressions that cannot be called dynamically in PHP. Let’s review them:

  • Variables
    • One of the most famous syntax: $$var, where $var contains a string with a valid variable name, which is used as the name of the second variable. This way, $a = 'b'; $b = 'c'; echo $$a; displays c;
    • extract() and compact()also allow conversion from variables to values and vice-versa.
  • Functions
    • This one is also quite famous: the function name should be in the variable. $function = 'foo'; $function() calls the foo function. Note that the full name of the function should be used, as no replacement will happen with the useexpressions;
  • Global constants
    • This one is a bit tricky, since constants have such a simple syntax. To dynamically call a constant, you need to use the constant() function. $a = 'E_ALL'; echo constant($a); does the job. In case of doubt, use the fully qualified name.
  • Instantiation
    • Instantiation may also use a variable, just like for function. It works with or without parenthesis, depending on the constructor signature. $classname = '\A\B'; $object = new $classname()`;
  • Instanceof
    • Instanceof checks if a variable contains an object of a certain class. The class name is the second argument, and it may very well be a variable that contains a string. $object instanceof $myClass::class.
  • namespace (definition)
    • The namespace MySpace, at the beginning of every PHP scripts nowadays, cannot be changed.
    • It is possible to create new namespaces at execution time. Either with define(), to create a constant in a non-existing namespace : it will then be created. define('\A\B', 1);
    • It is also possible to create dynamically namespaces for with classes, and their cousins (interfaces, traits, enums), with class_alias().Contrary to class_alias(), it will only copy an existing class. Yet, it creates new namespaces too.
    • I am not aware of any ways to create a new namespace for a function at execution time, short of using eval().
  • namespace (usage)
    • It is possible to use the namespace keyword in when calling anything (class, constant, function, etc.), and make sure that the call happens inside the current namespace. So, `echo namespace\E_ALL;' always fails, unless this code is in the global namespace.
  • Methods
    • Dynamic methods works just like functions, except that you need the object first and the parenthesis after. $method = 'm'; $object->$method();
  • Properties
    • Properties works just like methods. This time though, case is important. $property = 'p'; $object->$p; Note that it looks like a weird call, without the parenthesis to differentiate them from method calls.
    • It is also possible to call dynamically a property and re-route it to another. This is achieved with the magic methods __get() and __set().
    • Class constants may be turned into a non-constant value, simply by using an object as the ‘class’ part. So, echo $object::CONSTANT is literally resolved at execution time, even though it is a constant syntax.
    • Until PHP 8.3, there is only one way to call dynamically a class constant whose name is in a variable : constant('\className::'.$constantName).
    • Starting with PHP 8.3, there is a new syntax for dynamic constant calls : Class constantsclassName::{$constantName}
  • Arguments (in function call)
    • Use call_user_func() or call_user_func_array(), which take the function or method name as first argument, and the arguments as the next arguments (sic).
    • The second syntax is the ellipsis argument. The ‘three dots’  ... operators spreads the elements of the array, just like we would write is in the code. $function(...$args). In PHP 8.0, those arguments are positional and should be in the right order. In PHP 8.1, they are now taking advantage of the keys to give them names.
  • Parameters (in function definition)
    • The ‘three dots’  ... operators collects all the last arguments of an method call, into the last argument. function foo(...$all) { }
    • func_get_args() gives access to the list of arguments that were use at call time. This is the most versatile approach, where everything is possible and has to be done manually.
  • Eval()
    • The ultimate dynamic code of all, is the eval() function. This should be a last resort option, and given the previous entries, there are no good reason known to man to use it. eval() takes a string of PHP code, and executes it. This opens the door to huge freedom and great responsibility.

Some PHP syntax elements do no have any dynamic syntax:

  • type hints
  • class extensions
  • class implementation
  • class constant definition
  • enumeration cases
  • use expressions
  • most of the operators. Operators often have a function equivalent (think, ** versus pow()), so falling back to functions is a good way to go.

Most of those dynamic calls come with warnings: in terms of security, every dynamic element should be thouroughly checked before usage, to avoid problems of existence, or nefarious redirections. And, there is also a speed penalty, as PHP has to wait for execution time to actually do the work.