Can I do the following in PHP?
$lstrClassName = 'Class';
$lstrMethodName = 'function';
$laParameters = array('foo' => 1, 'bar' => 2);
$this->$lstrClassName->$lstrMethodName($laParameters);
The solution I'm using now, is by calling the function with eval() like so:
eval('$this->'.$lstrClassName.'->'.$lstrMethodName.'($laParameters);');
I'm curious if there is a beter way to solve this.
Thanks!
You don't need eval to do that ... depending on your version
Examples
class Test {
function hello() {
echo "Hello ";
}
function world() {
return new Foo ();
}
}
class Foo {
function world() {
echo " world" ;
return new Bar() ;
}
function baba() {
}
}
class Bar {
function world($name) {
echo $name;
}
}
$class = "Test";
$hello = "hello";
$world = "world";
$object = new $class ();
$object->$hello ();
$object->$world ()->$world ();
$object->$world ()->$world ()->$world(" baba ");
Output
Hello World baba
And if you are using PHP 5.4 you can just call it directly without having to declare variables
You might also want to look at call_user_func http://php.net/manual/en/function.call-user-func.php
Did you try your code? The best way to find out if something will work is by trying it. If you do try it, you will find that yes, it does work (assuming that $this has a property called Class which is an instance of an object that defines a method called function).
There are also the two functions call_user_func() and call_user_func_array()
I would suggest you call_user_func_array which can be used for functions and for arrays rather than eval.
However the syntax is different from what you suggested, and the fact that I tend to avoid eval while possible, you can use it with:
To call it with objects, just do it like:
$return=call_user_func_array(array($objInstance, "CLASSMETHOD"), $paramArray);
Untested but
this->$$lstrClassName->$$lstrMethodName($laParameters);
http://php.net/manual/en/language.variables.variable.php
Related
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Use a variable to define a PHP function
Use Variable as Function Name in PHP
I want to perform a conditional function call but I don't necessarily know what what the function will be, so that would be a long switch.
For example;
$userSelection = "calculator"; /* or "stocks" or whatever widget */
$widget->get_widget($userSelection);
public function __construct($userSelection){
/* pseudo code */
call function $userSelection();
}
public function calculator(){
/* Get Calculator */
}
Sure there is. This feature is called variable functions:
$functionName = "strlen";
$length = $$functionName("Hello world!");
The $$var(...) syntax is convenient, but it will only work with free functions. If you want to call a class method this way, you will need to use call_user_func or call_user_func_array (these functions can also handle the "free function" case).
Look at the call-user-func function. This allows you to call another function, e.g.
call_user_func('calculator')
call_user_func($userSelection);
http://php.net/manual/en/function.call-user-func.php
Take a look at this php functions:
call_user_func(): http://php.net/manual/de/function.call-user-func.php
call_user_func_array(): http://www.php.net/manual/de/function.call-user-func-array.php
create_function(): http://www.php.net/manual/de/function.create-function.php
There is also a direct (though ugly) execution syntax:
function some_func(args) {...}
$function_name='some_func';
$$function_name(args2);
You can use call_user_func() for that, like this:
$userSelection = "calculator";
call_user_func($userSelection[, $param1, $param2, ...]);
call_user_func_array($userSelection, $params);
If it's just a function you're after then using this should solve your problems
$function = "echo";
$$function "fooBar";
If it's a class method that you want to keep flexible use magic method __call() which will allow you to use method names that are not pre-defined.
__call() is triggered when invoking inaccessible methods in an object context.
i.e.
class Foo {
public function __call($name, $arguments) {
echo $name;
}
}
$foo = new Foo();
$foo->bar(); // will echo "bar"
PHP built-in function 'eval' can do everything, but beware of injection.
$var = "somefunction";
eval("$var();");
http://php.net/manual/en/function.eval.php
It's pretty simple if that's what you mean.
function calculator() {
echo 'foo';
}
$userSelection = "calculator";
if (function_exists($userSelection)) {
$userSelection();
}
Or within a class like in your example:
class widget {
public function __construct($userSelection) {
echo 'constructed widget<br>';
if (function_exists($userSelection)) {
$this->$userSelection();
}
}
public function calculator() {
echo 'bar';
}
}
$userSelection = "calculator";
$widget = new widget($userSelection);
Or from outside a class when the function is part of the class.
class widget {
public function calculator() {
echo 'bar';
}
}
$widget = new widget();
$userSelection = "calculator";
$widget->$userSelection();
I would work with if/else statements though to determine the function to be called just to be sure that only valid functions are executed (do you sanitize the user selection or do you just get it from a $_POST? The latter would be a very bad idea).
You can do following :
$var = 'abc';
switch ($var) {
case 'abc':
$result = $var('test param');
echo $result;
break;
default :
echo 'default';
break;
}
function abc($data) {
return $data;
}
I have a variable like $string = "blah";
How can I create a function that has the variable value as name?
Is this possible in PHP?
Like function $string($args){ ... } or something, and be able to call it like:
blah($args);
this might not be a good idea, but you can do something like this:
$string = "blah";
$args = "args"
$string = 'function ' . $string . "({$args}) { ... }";
eval($string);
That doesn't sound like a great design choice, it might be worth rethinking it, but...
If you're using PHP 5.3 you could use an anonymous function.
<?php
$functionName = "doStuff";
$$functionName = function($args) {
// Do stuff
};
$args = array();
$doStuff($args);
?>
Okay, challenge accepted!
No matter how weird the question is (it's not btw), let's take it seriously for a moment! It could be useful to have a class that can declare functions and make them real:
<?php
customFunctions::add("hello", // prepare function "hello"
function($what) {
print "Hello $what, as Ritchie said";
print "<br>";
}
);
customFunctions::add("goodbye", // prepare function "goodbye"
function($what,$when) {
print "Goodbye cruel $what, ";
print "I'm leaving you $when";
print "<br>";
}
);
eval(customFunctions::make()); // inevitable - but it's safe!
That's it! Now they're real functions. No $-prefixing, no runtime evaluations whenever they get called - eval() was only needed once, for declaration. After that, they work like any function.
Let's try them:
hello('World'); // "Hello World"
goodbye('world','today'); // "Goodbye cruel world, I'm leaving you today"
Magic behind
Here's the class that can do this. Really not a complex one:
class customFunctions {
private static $store = [];
private static $maker = "";
private static $declaration = '
function %s() {
return call_user_func_array(
%s::get(__FUNCTION__),
func_get_args()
);
}
';
private static function safeName($name) {
// extra safety against bad function names
$name = preg_replace('/[^a-zA-Z0-9_]/',"",$name);
$name = substr($name,0,64);
return $name;
}
public static function add($name,$func) {
// prepares a new function for make()
$name = self::safeName($name);
self::$store[$name] = $func;
self::$maker.=sprintf(self::$declaration,$name,__CLASS__);
}
public static function get($name) {
// returns a stored callable
return self::$store[$name];
}
public static function make() {
// returns a string with all declarations
return self::$maker;
}
}
It provides an inner storage for your functions, and then declare "real" functions that call them. This is something similar to fardjad's solution, but with real code (not strings) and therefore a lot more convenient & readable.
Try call_user_func_array()
php.net link
You can call a function by its name stored in a variable, and you can also assign a function to variables and call it using the variable. If it's not what you want, please explain more.
Is it possible to add methods to functions?
For example:
<?
function func(){
;
}
//add method
func->test = function(){
;
}
func->test();
func();
I'm coming from a javascript background, and therefore I'm used to 'everything is an object'.
EDIT:
I was just explaining where the misconception may often come from for new phpers. I understand the above code doesn't work.
EDIT 2
Figured it out.
class myfunc_class{
function __invoke(){
//function body
}
function __call($closure, $args)
{
call_user_func_array($this->$closure, $args);
}
}
$func = new myfunc_class;
$func->test = function(){
echo '<br>test<br>';
};
$func->test();
$func();
Even sexier :)
class func{
public $_function;
function __invoke(){
return call_user_func_array($this->_function,func_get_args());
}
function __construct($fun){
$this->_function = $fun;
}
function __call($closure, $args)
{
call_user_func_array($this->$closure, $args);
}
}
$func = new func(function($value){
echo $value;
});
$func->method = function(){
echo '<br>test<br>';
};
$func('someValue');
$func->method();
No.
Not everything is an object in PHP. In fact the only thing that is an object is, well, an object. More specifically, and generally, an instantiation of a class.
Your code converted to PHP
// function_object.php
<?php
class FunctionObject {
public method func() {
// do stuff
}
}
?>
In other code you would use it like this:
<?php
// example.php in same folder as function_object.php
include 'function_object.php';
$FuncObj = new FunctionObject;
$FuncObj->func();
Also: read more about PHP & OOP
No, because an object is a different PHP language construct than a function. Functions do not have properties, but are instead simply execution instructions.
But, if func were instead a pre-defined class, then yes... with a bit of witchcraft, ignoring public outcry, foregoing readability and PHP coding standards, and by using closures with the __call() magic method...
class func
{
function __call($func, $args)
{
return call_user_func_array($this->$func, $args);
}
}
$obj = new func;
$obj->test = function($param1, $param2)
{
return $param1 + $param2;
};
echo $obj->test(1,1);
This won't work as you'd think without __call(), because by $obj->test(1,1), PHP thinks you're trying to call a non-existent method of func when out of object scope. But inside, being that the new "test" property is of a type: closure, the call_user_func_array() just sees the "test" property as just another function, so you can hide this bit of trickery from outside scope.
You would need your function func() to return an object, then you'd be able to do something like: func()->test();
But please note that your way of handling objects is not right in PHP and I suggest that you go read the OO documentations here.
In difference to javacript, in PHP not everything is an object. Therefore you need to differ between function and class.
If you want to create an object, you need to define the class first.
class myClass {
}
You can then add as many functions to the class as you need. But you need to define them first:
class myClass {
function test() {
echo "test!\n";
}
}
When everything is ready, you can bring it to life then:
$class = new myClass;
$class->test();
Checkout the manual for more.
You can't do what you're trying to do, but you can define functions inside of other functions.
This example outputs text:
function a() {
function b() { echo 'Hi'; }
}
a();
b();
Output: HiHi
This example outputs an error:
function a() {
function b() { echo 'Hi'; }
}
b();
Output: ERROR
I am just starting out with PHP, and I am wondering if there is a way to add an anonymous function to a class instance.
For instance, lets say...
class A{
public B;
}
$c = new A();
//This is where I am getting a little confused...
//The following wont work
$c->B = function(){echo('HelloWorld');};
$c->B();
What I am hoping to do is reuse the same spit of code in a great number of different applications, and make it so that I can just 'swap-out' and replace functions in specific instances.
I am using php5.3 (so anonymous functions should work, just not in the way that I am using them).
Thanks so very much for your time!!
-GK
You can use the __call magic function for this job. Not a beauty, but it works..
like this:
class A {
public $B;
public function __call($closure, $args)
{
call_user_func_array($this->$closure, $args);
}
}
$c = new A();
$c->B = function () { echo('HelloWorld'); };
$c->B();
FWIW:
PHP 5.3's treatment of anonymous functions is entertaining. This won't work:
$c->B = function() { echo func_get_arg(0); };
$c->B("This fails :(");
This WILL work:
$c->B = function() { echo func_get_arg(0); };
$hilarious = $c->B;
$hilarious("This works!");
To work around this, you need to use a __call hack like the one provided by Oden.
This behavior may change in the future. The array dereferencing RFC was recently committed to PHP's trunk, and the patch has set off a discussion on function call chaining, the syntax of which may allow what you're trying to do without the __call hack. Unfortunately it's proven difficult in the past to get function call chaining working.
# real ugly, but PoC...
class a {
function __call($f, $x) {
call_user_func_array($this->$f, $x);
}
}
$a = new a;
$a->b = function() { echo "Hello world"; };
$a->b();
Sounds like you are describing a Strategy Pattern or Decorator Pattern - there are other ways to achieve this in way which is more easily communicated with other developers who read your code.
You can do something along these lines (which will also work with callbacks that are not closures):
<?php
class A {
private $fun;
function setFun($fun) {
if (!is_callable($fun))
throw new InvalidArgumentException();
$this->fun = $fun;
}
public function fun() {
call_user_func_array($this->fun, func_get_args());
}
}
$c = new A();
$c->setFun(function($a) { echo('HelloWorld ' . $a);});
$c->fun("here");
which gives HelloWorld here.
That said, you should also consider inheritance or the decorator pattern.
This is not an issue anymore by PHP 7;
// no error
$result = ($this->anonFunc)();
$result = ($this->anonFunc)($arg1, $arg2, ...);
See more about AST.
Rather than hooking a __call magic method into your class, you can instead execute the callable directly using call_user_func.
class A {
public $b;
}
$c = new A();
$c->b = function(){echo('HelloWorld');};
call_user_func($c->b); // HelloWorld
Obviously it would be nice for PHP to provide some syntax to execute this directly.
I know this question sounds rather vague so I will make it more clear with an example:
$var = 'bar';
$bar = new {$var}Class('var for __construct()'); //$bar = new barClass('var for __construct()');
This is what I want to do. How would you do it? I could off course use eval() like this:
$var = 'bar';
eval('$bar = new '.$var.'Class(\'var for __construct()\');');
But I'd rather stay away from eval(). Is there any way to do this without eval()?
Put the classname into a variable first:
$classname=$var.'Class';
$bar=new $classname("xyz");
This is often the sort of thing you'll see wrapped up in a Factory pattern.
See Namespaces and dynamic language features for further details.
If You Use Namespaces
In my own findings, I think it's good to mention that you (as far as I can tell) must declare the full namespace path of a class.
MyClass.php
namespace com\company\lib;
class MyClass {
}
index.php
namespace com\company\lib;
//Works fine
$i = new MyClass();
$cname = 'MyClass';
//Errors
//$i = new $cname;
//Works fine
$cname = "com\\company\\lib\\".$cname;
$i = new $cname;
How to pass dynamic constructor parameters too
If you want to pass dynamic constructor parameters to the class, you can use this code:
$reflectionClass = new ReflectionClass($className);
$module = $reflectionClass->newInstanceArgs($arrayOfConstructorParameters);
More information on dynamic classes and parameters
PHP >= 5.6
As of PHP 5.6 you can simplify this even more by using Argument Unpacking:
// The "..." is part of the language and indicates an argument array to unpack.
$module = new $className(...$arrayOfConstructorParameters);
Thanks to DisgruntledGoat for pointing that out.
class Test {
public function yo() {
return 'yoes';
}
}
$var = 'Test';
$obj = new $var();
echo $obj->yo(); //yoes
I would recommend the call_user_func() or call_user_func_arrayphp methods.
You can check them out here (call_user_func_array , call_user_func).
example
class Foo {
static public function test() {
print "Hello world!\n";
}
}
call_user_func('Foo::test');//FOO is the class, test is the method both separated by ::
//or
call_user_func(array('Foo', 'test'));//alternatively you can pass the class and method as an array
If you have arguments you are passing to the method , then use the call_user_func_array() function.
example.
class foo {
function bar($arg, $arg2) {
echo __METHOD__, " got $arg and $arg2\n";
}
}
// Call the $foo->bar() method with 2 arguments
call_user_func_array(array("foo", "bar"), array("three", "four"));
//or
//FOO is the class, bar is the method both separated by ::
call_user_func_array("foo::bar"), array("three", "four"));