How to call a closure that is a class variable? - php

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);

Related

Why can't I directly invoke an instantiated class in a test? [duplicate]

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);

calling an anonymous function stored in a class variable [duplicate]

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);

Calling a Wordpress function out of class

I have a woocommerce plugin that has a class Foo:
function wc_foo_init(){
class WC_Foo extends WC_Shipping_Method{
$var=get_option(); //gets an option for this session
function sayHello(){
echo $var;
}
new WC_Foo();
}
I want to call sayHello() out of the Foo class:
function bar(){
WC_Foo->sayHello();
}
But I get this error:
Fatal error: Call to a member function `sayHello` on a non-object.
You must instantiate class before make call of its methods:
$foo = new WC_Foo();
$foo->sayHello();
or if your php version is greater than 5.4 you can do:
(new WC_Foo())->sayHello();
Use $this selector if you are calling the method within the class
function bar(){
$this->sayHello();
}
If you want to call the method from other place,
you need to instantiate the class like this:
$object = new WC_Foo();
$object->sayHello();
Or make the method static like this:
public static function sayHello(){
echo "Hello";
}
And call it like this:
WC_Foo::sayHello();
// this way you dont need $object = new WC_Foo();
This might not be the full code, so it's pretty weird what you have there, but let's go.
Since you have a function to init your object, you would probably want to at least return that instance. This code might help you understand:
function init_foo(){
class foo{
function say(){
echo 'hello';
}
}
$foo1 = new Foo();
return $foo1;
}
function bar($foo3){
$foo3->say();
}
$foo2 = init_foo();
bar($foo2);
So, first we create the object and return it. Then we inject it in the bar function, just needing to call the method after that. (I used different var names so it's easier to understand scope)

PHP Closure On Class Instance

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();

Having Issues with Magic Static Functions

I have a class that I'm trying to create a function that will call a static method that is run through a magic method. The thing is the functions work as long as they are from different types of classes than the class calling them, but if I call a static function of the same class all the function will return is 1.
class Test {
public function static __callStatic($name, $params) {
return 2;
}
public function __call($name, $params) {
return 1;
}
public function Test1() {
return Test::GetTwo();
}
}
class Test2 {
public function Test() {
return Test::GetTwo();
}
}
$t = new Test();
echo $t->Test1(); //prints 1 should be 2
$t2 = new Test2();
echo $t->Test(); //prints 2 as it should
even if the static method GetTwo() returns an object I still get 1 if I'm calling a function in the same scope as Test1(). Any one else run into this?
echo Test::Test1();
You don't need (nor should use) an instance to call a static method. Use the class and the scope resolution operator (::) to do the call.
If you need late static binding use static::Test1();
For an method call on an instance, PHP will try the following:
Find an instance method named X.
Find a magic method __call.
Find a class (static) method named X.
Find a magic class (static) method __callStatic.
In your case, it finds __call at step 2 and goes with that.

Categories