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;
displaysc
; extract()
andcompact()
also allow conversion from variables to values and vice-versa.
- One of the most famous syntax:
- Functions
- This one is also quite famous: the function name should be in the variable.
$function = 'foo'; $function()
calls thefoo
function. Note that the full name of the function should be used, as no replacement will happen with theuse
expressions;
- This one is also quite famous: the function name should be in the variable.
- 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.
- This one is a bit tricky, since constants have such a simple syntax. To dynamically call a constant, you need to use the
- 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()`;
- Instantiation may also use a variable, just like for function. It works with or without parenthesis, depending on the constructor signature.
- 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
.
- 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.
- 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 toclass_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()
.
- The
- 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.
- It is possible to use the
- Methods
- Dynamic methods works just like functions, except that you need the object first and the parenthesis after.
$method = 'm'; $object->$method();
- Dynamic methods works just like functions, except that you need the object first and the parenthesis after.
- 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 constants
className::{$constantName}
- Properties works just like methods. This time though, case is important.
- Arguments (in function call)
- Use
call_user_func()
orcall_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.
- Use
- 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.
- The ‘three dots’
- 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.
- The ultimate dynamic code of all, is the
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.