If I have a class like:
class MyClass
{
public function foo()
{
echo "foo";
}
}
And then outside of the class instantiate it and try to create an anonymous function in it:
$mine = new MyClass();
$mine->bar = function() {
echo "bar";
}
And then try to call it like $mine->bar(), I get:
Fatal error: Call to undefined method MyClass::bar() in ...
How can I create an anonymous function / closure on a class instance?
Aside: Before you tell me I should rethink my logic or use interfaces and OOP properly, in my case, it's a convenience method that applies to this specific instance of a bastardized class in an attempt to clean-up a legacy procedural application. And yes, I'm using PHP 5.3+
See my blog article here: http://blog.flowl.info/2013/php-container-class-anonymous-function-lambda-support/
You need to add a magic __call function:
public function __call($func, $args) {
return call_user_func($this->$func, $args);
}
The problem is that within this construct you can call private methods from public scope.
I suggest not to simply add new variables to a class that are not defined. You can avoid this using magic __set functions and catch all undefined variables in a container (= array, like in my blog post) and change the call_user_func behaviour to call only inside the array:
// inside class:
public $members = array();
public function __call($func, $args) {
// note the difference of calling only inside members:
return call_user_func($this->members[$func], $args);
}
__call
This will work.
class Foo {
public $bar;
public function __construct()
{
$this->bar = function()
{
echo 'closure called';
};
$this->bar();
}
public function __call($method, $args) {
return call_user_func($this->$method, $args);
}
}
new Foo();
The function IS being created.
PHP has a problem with calling it.
Dirty, but works:
$f = $mine->bar;
$f();
Related
class MyClass {
var $lambda;
function __construct() {
$this->lambda = function() {echo 'hello world';};
// no errors here, so I assume that this is legal
}
}
$myInstance = new MyClass();
$myInstance->lambda();
//Fatal error: Call to undefined method MyClass::lambda()
So what is the correct syntax for reaching class variables ?
In PHP, methods and properties are in a separate namespace (you can have a method and a property with the same name), and whether you are accessing a property or a method depends of the syntax you are using to do so.
$expr->something() is a method call, so PHP will search something in the class' list of methods.
$expr->something is a property fetch, so PHP will search something in the class' list of properties.
$myInstance->lambda(); is parsed as a method call, so PHP searches for a method named lambda in your class, but there is no such method (hence the Call to undefined method error).
So you have to use the fetch property syntax to fetch the lambda, and then call it.
Since PHP 7.0, you can do this with ($obj->lambda)():
($obj->lambda)();
The parentheses make sure that PHP parses ($obj->lambda) as fetch the property named lambda. Then, () calls the result of fetching the property.
or you can do this with ->lambda->__invoke():
$myInstance = new MyClass();
$myInstance->lambda->__invoke();
__invoke is one of PHP's magic methods. When an object implements this method, it becomes invokable: it can be called using the $var() syntax. Anonymous functions are instances of Closure, which implements __invoke.
Or assign it to a local variable:
$lambda = $myInstance->lambda;
$lambda();
Or call it using call_user_func:
call_user_func($myInstance->lambda);
call_user_func can call any callable, including anonymous functions.
Alternatively, if this is a common pattern in your code, you can setup a __call method to forward calls to your lambda:
class MyClass
{
private $lambda;
public function __construct()
{
$this->lambda = function() {
echo "Hello world!\n";
};
}
public function __call($name, $args)
{
return call_user_func_array($this->$name, $args);
}
}
Now this works:
$myInstance = new MyClass();
$myInstance->lambda();
Since PHP 5.4 you can even do that in a trait:
trait LambdasAsMethods
{
public function __call($name, $args)
{
return call_user_func_array($this->$name, $args);
}
}
class MyClass
{
use LambdasAsMethods;
private $lambda;
public function __construct()
{
$this->lambda = function() {
echo "Hello World!\n";
};
}
}
$myInstance = new MyClass();
$myInstance->lambda();
You can also call your lambda function without change something in your class, using ReflectionFunction.
$myInstance = new MyClass();
$lambda = new ReflectionFunction($myInstance->lambda);
$lambda->invoke();
or if you have to pass arguments then
$args = array('arg'=>'value');
$lambda->invokeArgs($args);
class MyClass {
var $lambda;
function __construct() {
$this->lambda = function() {echo 'hello world';};
// no errors here, so I assume that this is legal
}
}
$myInstance = new MyClass();
$myInstance->lambda();
//Fatal error: Call to undefined method MyClass::lambda()
So what is the correct syntax for reaching class variables ?
In PHP, methods and properties are in a separate namespace (you can have a method and a property with the same name), and whether you are accessing a property or a method depends of the syntax you are using to do so.
$expr->something() is a method call, so PHP will search something in the class' list of methods.
$expr->something is a property fetch, so PHP will search something in the class' list of properties.
$myInstance->lambda(); is parsed as a method call, so PHP searches for a method named lambda in your class, but there is no such method (hence the Call to undefined method error).
So you have to use the fetch property syntax to fetch the lambda, and then call it.
Since PHP 7.0, you can do this with ($obj->lambda)():
($obj->lambda)();
The parentheses make sure that PHP parses ($obj->lambda) as fetch the property named lambda. Then, () calls the result of fetching the property.
or you can do this with ->lambda->__invoke():
$myInstance = new MyClass();
$myInstance->lambda->__invoke();
__invoke is one of PHP's magic methods. When an object implements this method, it becomes invokable: it can be called using the $var() syntax. Anonymous functions are instances of Closure, which implements __invoke.
Or assign it to a local variable:
$lambda = $myInstance->lambda;
$lambda();
Or call it using call_user_func:
call_user_func($myInstance->lambda);
call_user_func can call any callable, including anonymous functions.
Alternatively, if this is a common pattern in your code, you can setup a __call method to forward calls to your lambda:
class MyClass
{
private $lambda;
public function __construct()
{
$this->lambda = function() {
echo "Hello world!\n";
};
}
public function __call($name, $args)
{
return call_user_func_array($this->$name, $args);
}
}
Now this works:
$myInstance = new MyClass();
$myInstance->lambda();
Since PHP 5.4 you can even do that in a trait:
trait LambdasAsMethods
{
public function __call($name, $args)
{
return call_user_func_array($this->$name, $args);
}
}
class MyClass
{
use LambdasAsMethods;
private $lambda;
public function __construct()
{
$this->lambda = function() {
echo "Hello World!\n";
};
}
}
$myInstance = new MyClass();
$myInstance->lambda();
You can also call your lambda function without change something in your class, using ReflectionFunction.
$myInstance = new MyClass();
$lambda = new ReflectionFunction($myInstance->lambda);
$lambda->invoke();
or if you have to pass arguments then
$args = array('arg'=>'value');
$lambda->invokeArgs($args);
I have a class with a few methods that take an anonymous function as a parameter. The class looks like this:
class MyClass {
public function myMethod($param, $func) {
echo $param;
user_call_func($func);
}
public function sayHello() {
echo "Hello from MyClass";
}
}
I'd like to be able to do things like this:
$obj = new MyClass;
$obj->myMethod("Hi", function($obj) {
echo "I'm in this anonymous function";
// let's use a method from myClass
$obj->sayHello();
});
So, in my anonymous function, since I passed $obj as a parameter to the anonymous function, I should be able to access its methods from within the anonymous function. In this case we'd see
I'm in this anonymous function
Hello from MyClass
How would I achieve this?
Thanks
Use the use construct:
$self = $this;
$obj->myMethod("Hi", function($obj) use($self) {
echo "I'm in this anonymous function";
// let's use a method from myClass
$obj->sayHello();
});
You've got to capture $this in another variable because use doesn't allow $this to be passed in, unless you are using PHP >= 5.4. Relevant quote from the documentation:
Closures may also inherit variables from the parent scope. Any such
variables must be passed to the use language construct. Inheriting
variables from the parent scope is not the same as using global
variables. Global variables exist in the global scope, which is the
same no matter what function is executing. The parent scope of a
closure is the function in which the closure was declared (not
necessarily the function it was called from).
Update
It may also be helpful to know that you retain the visibility of the class that you're currently in when the anonymous function is executing, as demonstrated in this simple script:
class Test
{
public function testMe()
{
$self = $this;
$tester = function() use($self) {
$self->iAmPrivate();
};
$tester();
}
private function iAmPrivate()
{
echo 'I can see my own private parts!';
}
}
$test = new Test;
$test->testMe();
Output:
I can see my own private parts!
I'm trying to use myVar inside my of a method's function. I have already tried adding global but still nothing. I know this is probably basic but I can't seem to find it.
class myClass{
public $myVar;
public function myFunction() {
function myInnerFunction() {
//how do I use this variable here
echo $this->myVar;
}
}
}
Whenever I try using $this I get this error: 'Using $this when not in object context in...'
You should use $this->myVar
See the PHP Documentation - The Basics
<?php
class SimpleClass
{
// property declaration
public $var = 'a default value';
// method declaration
public function displayVar() {
echo $this->var;
}
}
?>
The pseudo-variable $this is available when a method is called from
within an object context. $this is a reference to the calling object
(usually the object to which the method belongs
Update:
In your new code sample, myInnerFunction is a nested function and is not accessible until the myFunction method is called. Once the myFunction method is called, the myInnerFunction becomes part of the global scope.
Maybe this is what you are looking for:
class myClass{
public $myVar;
public function myFunction() {
}
function myInnerFunction() {
//how do I use this variable here
echo $this->myVar;
}
}
Inner functions like myInnerFunction are always global in scope, even if they are defined inside of a member function in a class. See this question for another similar example
So, to PHP, the following are (almost) equivalent:
class myClass{
public $myVar;
public function myFunction() {
function myInnerFunction() {
//how do I use this variable here
echo $this->myVar;
}
}
}
And
class myClass{
public $myVar;
public function myFunction() {
}
}
function myInnerFunction() {
//how do I use this variable here
echo $this->myVar;
}
Hopefully the second example illustrates why $this is not even in scope for myInnerFunction. The solution is simply to pass the variable as a parameter to the function.
Pass it as an argument to the inner function.
You can use ReflectionProperty:
$prop = new ReflectionProperty("SimpleClass", 'var');
Full example:
class myClass{
public $myVar;
public function myFunction() {
function myInnerFunction() {
//how do I use this variable here
$prop = new ReflectionProperty("SimpleClass", 'myVar');
}
}
}
The solution above is good when you need each instance to have an own value. If you need all instances to have a same you can use static:
class myClass
{
public static $myVar = "this is my var's value";
public function myClass() {
echo self::$myVar;
}
}
new myClass();
see here
class MyClass {
var $lambda;
function __construct() {
$this->lambda = function() {echo 'hello world';};
// no errors here, so I assume that this is legal
}
}
$myInstance = new MyClass();
$myInstance->lambda();
//Fatal error: Call to undefined method MyClass::lambda()
So what is the correct syntax for reaching class variables ?
In PHP, methods and properties are in a separate namespace (you can have a method and a property with the same name), and whether you are accessing a property or a method depends of the syntax you are using to do so.
$expr->something() is a method call, so PHP will search something in the class' list of methods.
$expr->something is a property fetch, so PHP will search something in the class' list of properties.
$myInstance->lambda(); is parsed as a method call, so PHP searches for a method named lambda in your class, but there is no such method (hence the Call to undefined method error).
So you have to use the fetch property syntax to fetch the lambda, and then call it.
Since PHP 7.0, you can do this with ($obj->lambda)():
($obj->lambda)();
The parentheses make sure that PHP parses ($obj->lambda) as fetch the property named lambda. Then, () calls the result of fetching the property.
or you can do this with ->lambda->__invoke():
$myInstance = new MyClass();
$myInstance->lambda->__invoke();
__invoke is one of PHP's magic methods. When an object implements this method, it becomes invokable: it can be called using the $var() syntax. Anonymous functions are instances of Closure, which implements __invoke.
Or assign it to a local variable:
$lambda = $myInstance->lambda;
$lambda();
Or call it using call_user_func:
call_user_func($myInstance->lambda);
call_user_func can call any callable, including anonymous functions.
Alternatively, if this is a common pattern in your code, you can setup a __call method to forward calls to your lambda:
class MyClass
{
private $lambda;
public function __construct()
{
$this->lambda = function() {
echo "Hello world!\n";
};
}
public function __call($name, $args)
{
return call_user_func_array($this->$name, $args);
}
}
Now this works:
$myInstance = new MyClass();
$myInstance->lambda();
Since PHP 5.4 you can even do that in a trait:
trait LambdasAsMethods
{
public function __call($name, $args)
{
return call_user_func_array($this->$name, $args);
}
}
class MyClass
{
use LambdasAsMethods;
private $lambda;
public function __construct()
{
$this->lambda = function() {
echo "Hello World!\n";
};
}
}
$myInstance = new MyClass();
$myInstance->lambda();
You can also call your lambda function without change something in your class, using ReflectionFunction.
$myInstance = new MyClass();
$lambda = new ReflectionFunction($myInstance->lambda);
$lambda->invoke();
or if you have to pass arguments then
$args = array('arg'=>'value');
$lambda->invokeArgs($args);