I use eval()
in my current project like this:
if (class_exists($class_name)) //$class_name depends on user input
eval($class_name.'::MyStaticMethod()');
eval()
is executed if and only if class with the name $class_name
exists so it's kinda safe, but I still don't think that this is the best solution.
Can I do the same what code above does without eval()
?
I have recently answered this question. The last part of my answer perfectly answers this question and is much more useful for future readers than answers provided here. That's why I am answering my own question.
PHP has features that gives possibility to avoid using eval
in most cases:
PHP is very dynamic language. It has ability to do following stuff with strings
:
Define and/or get variable (supported from PHP 4.3). For example:
$variableName = 'MyVariable';
// Create new variable with the name defined in variable $variableName
${$variableName} = 'MyValue';
//Outputs: string(7) "MyValue"
var_dump($MyVariable);
//Outputs: string(7) "MyValue"
var_dump(${'MyVariable'});
Demo
Call function (supported from PHP 4.3). For example:
// Create function with the name defined in variable $functionName
function MyFunction($argument) {
return 'Argument passed is: '.$argument;
}
$functionName = 'MyFunction';
// Outputs:
// string(48) "Argument passed is: Calling MyFunction directly."
var_dump(MyFunction('Calling MyFunction directly.'));
// Outputs:
// string(51) "Argument passed is: Calling MyFunction with string."
var_dump($functionName('Calling MyFunction with string.'));
Demo
Create instance of class (supported from PHP 5.0). For example:
class MyClass {
public function __construct() {
echo 'Constructing MyClass'."\n";
}
}
$className = 'MyClass';
$objFromString = new $className();
// Outputs: object(MyClass)#1 (0) {}
var_dump($objFromString);
Demo
Call static method (supported from PHP 5.0). For example:
class MyClass {
public static function staticMethod() {
return 'MyClass::staticMethod called';
}
}
$staticMethodName = 'staticMethod';
// Outputs: string(28) "MyClass::staticMethod called"
var_dump(MyClass::$staticMethodName());
Demo
And from PHP 5.3 class name can also be defined by string. Example:
class MyClass {
public static function staticMethod() {
return 'MyClass::staticMethod called';
}
}
$className = 'MyClass';
$staticMethodName = 'staticMethod';
var_dump($className::$staticMethodName());
var_dump($className::staticMethod());
Demo
Call instance method of object (supported from PHP 5.0). For example:
class MyClass {
public function instanceMethod() {
return 'MyClass::instanceMethod called';
}
}
$methodName = 'instanceMethod';
$obj = new MyClass();
// Outputs: string(30) "MyClass::instanceMethod called"
var_dump($obj->$methodName());
Demo
Access static and instance properties of object (supported from PHP 5.0). For example:
class MyClass {
public static $myStaticProperty;
public $myInstanceProperty;
}
$staticPropertyName = 'myStaticProperty';
$instancePropertyName = 'myInstanceProperty';
MyClass::${$staticPropertyName} = 'my static value';
$obj = new MyClass();
$obj->{$instancePropertyName} = 'my instance value';
var_dump(MyClass::${$staticPropertyName});
var_dump($obj->{$instancePropertyName});
Demo
- PHP has two functions:
call_user_func
and call_user_func_array
for dynamic function/method calls. Both are perfectly documented so I won't go in details here.
- Even if everything above is not enough PHP 5 comes with great
Reflection
API. Unfortunately, documentation has few examples but reflection is quite large topic to cover here. Basically, It's not a big deal to use reflection after reading how it works.
I'd suggest call_user_func
.
An alternative to call_user_func()
would be calling it like this:
$class_and_method = 'Class::MyStaticMethod()';
$class_and_method();
yes:
call_user_func(array($class_name, 'MyStaticMethod'));
As of PHP 5.3+,
$class_name::MyStaticMethod();
Adisory:
userinput + eval = security hole;
Also eval is an expensive operation requiring parsing the string into an actionable format (parse tree, abstract syntax tree, etc.) and executing the new found logic.
You don't want to eval every little tidbit of code. Use eval if you have something for it to chew on or rather put that logic somewhere where it's reusable and parametrized such as a function.
Also as of php 5.4
$method = array('class_name', 'method_name');
$method(); // calls class_name::method_name()