Php call closure object

The Closure class

Anonymous functions yield objects of this type. This class has methods that allow further control of the anonymous function after it has been created.

Besides the methods listed here, this class also has an __invoke method. This is for consistency with other classes that implement calling magic, as this method is not used for calling the function.

Class synopsis

public static bind ( Closure $closure , ? object $newThis , object | string | null $newScope = «static» ): ? Closure

Table of Contents

  • Closure::__construct — Constructor that disallows instantiation
  • Closure::bind — Duplicates a closure with a specific bound object and class scope
  • Closure::bindTo — Duplicates the closure with a new bound object and class scope
  • Closure::call — Binds and calls the closure
  • Closure::fromCallable — Converts a callable into a closure

User Contributed Notes 4 notes

This caused me some confusion a while back when I was still learning what closures were and how to use them, but what is referred to as a closure in PHP isn’t the same thing as what they call closures in other languages (E.G. JavaScript).

In JavaScript, a closure can be thought of as a scope, when you define a function, it silently inherits the scope it’s defined in, which is called its closure, and it retains that no matter where it’s used. It’s possible for multiple functions to share the same closure, and they can have access to multiple closures as long as they are within their accessible scope.

In PHP, a closure is a callable class, to which you’ve bound your parameters manually.

It’s a slight distinction but one I feel bears mentioning.

Small little trick. You can use a closures in itself via reference.

Example to delete a directory with all subdirectories and files:

Источник

Php call closure object

Watch out when ‘importing’ variables to a closure’s scope — it’s easy to miss / forget that they are actually being *copied* into the closure’s scope, rather than just being made available.

So you will need to explicitly pass them in by reference if your closure cares about their contents over time:

$one (); // outputs NULL: $result is not in scope
$two (); // outputs int(0): $result was copied
$three (); // outputs int(1)
?>

Another less trivial example with objects (what I actually tripped up on):

//set up variable in advance
$myInstance = null ;

$broken = function() uses ( $myInstance )
if(!empty( $myInstance )) $myInstance -> doSomething ();
>;

//$myInstance might be instantiated, might not be
if( SomeBusinessLogic :: worked () == true )
$myInstance = new myClass ();
>

$broken (); // will never do anything: $myInstance will ALWAYS be null inside this closure.
$working (); // will call doSomething if $myInstance is instantiated

/*
(string) $name Name of the function that you will add to class.
Usage : $Foo->add(function()<>,$name);
This will add a public function in Foo Class.
*/
class Foo
public function add ( $func , $name )
$this -> < $name >= $func ;
>
public function __call ( $func , $arguments ) call_user_func_array ( $this ->< $func >, $arguments );
>
>
$Foo = new Foo ();
$Foo -> add (function() echo «Hello World» ;
>, «helloWorldFunction» );
$Foo -> add (function( $parameterone ) echo $parameterone ;
>, «exampleFunction» );
$Foo -> helloWorldFunction (); /*Output : Hello World*/
$Foo -> exampleFunction ( «Hello PHP» ); /*Output : Hello PHP*/
?>

Читайте также:  Https reports 43edu ru projects reports letter1903zpo php pp f1

In case you were wondering (cause i was), anonymous functions can return references just like named functions can. Simply use the & the same way you would for a named function. right after the `function` keyword (and right before the nonexistent name).

$x =& $fn ();
var_dump ( $x , $value ); // ‘int(0)’, ‘int(0)’
++ $x ;
var_dump ( $x , $value ); // ‘int(1)’, ‘int(1)’

Every instance of a lambda has own instance of static variables. This provides for great event handlers, accumulators, etc., etc.

Creating new lambda with function() < . >; expression creates new instance of its static variables. Assigning a lambda to a variable does not create a new instance. A lambda is object of class Closure, and assigning lambdas to variables has the same semantics as assigning object instance to variables.

Example script: $a and $b have separate instances of static variables, thus produce different output. However $b and $c share their instance of static variables — because $c is refers to the same object of class Closure as $b — thus produce the same output.

function generate_lambda () : Closure
# creates new instance of lambda
return function( $v = null ) static $stored ;
if ( $v !== null )
$stored = $v ;
return $stored ;
>;
>

$a = generate_lambda (); # creates new instance of statics
$b = generate_lambda (); # creates new instance of statics
$c = $b ; # uses the same instance of statics as $b

$a ( ‘test AAA’ );
$b ( ‘test BBB’ );
$c ( ‘test CCC’ ); # this overwrites content held by $b, because it refers to the same object

var_dump ([ $a (), $b (), $c () ]);
?>

This test script outputs:
array(3) [0]=>
string(8) «test AAA»
[1]=>
string(8) «test CCC»
[2]=>
string(8) «test CCC»
>

/*
* An example showing how to use closures to implement a Python-like decorator
* pattern.
*
* My goal was that you should be able to decorate a function with any
* other function, then call the decorated function directly:
*
* Define function: $foo = function($a, $b, $c, . ) <. >
* Define decorator: $decorator = function($func) <. >
* Decorate it: $foo = $decorator($foo)
* Call it: $foo($a, $b, $c, . )
*
* This example show an authentication decorator for a service, using a simple
* mock session and mock service.
*/

/*
* Define an example decorator. A decorator function should take the form:
* $decorator = function($func) * return function() use $func) * // Do something, then call the decorated function when needed:
* $args = func_get_args($func);
* call_user_func_array($func, $args);
* // Do something else.
* >;
* >;
*/
$authorise = function( $func ) return function() use ( $func ) if ( $_SESSION [ ‘is_authorised’ ] == true ) $args = func_get_args ( $func );
call_user_func_array ( $func , $args );
>
else echo «Access Denied» ;
>
>;
>;

/*
* Define a function to be decorated, in this example a mock service that
* need to be authorised.
*/
$service = function( $foo ) echo «Service returns: $foo » ;
>;

/*
* Decorate it. Ensure you replace the origin function reference with the
* decorated function; ie just $authorise($service) won’t work, so do
* $service = $authorise($service)
*/
$service = $authorise ( $service );

/*
* Establish mock authorisation, call the service; should get
* ‘Service returns: test 1’.
*/
$_SESSION [ ‘is_authorised’ ] = true ;
$service ( ‘test 1’ );

Читайте также:  Use property value in java

/*
* Remove mock authorisation, call the service; should get ‘Access Denied’.
*/
$_SESSION [ ‘is_authorised’ ] = false ;
$service ( ‘test 2’ );

Beware of using $this in anonymous functions assigned to a static variable.

class Foo public function bar () static $anonymous = null ;
if ( $anonymous === null ) // Expression is not allowed as static initializer workaround
$anonymous = function () return $this ;
>;
>
return $anonymous ();
>
>

$a = new Foo ();
$b = new Foo ();
var_dump ( $a -> bar () === $a ); // True
var_dump ( $b -> bar () === $a ); // Also true
?>

In a static anonymous function, $this will be the value of whatever object instance that method was called on first.

To get the behaviour you’re probably expecting, you need to pass the $this context into the function.

class Foo public function bar () static $anonymous = null ;
if ( $anonymous === null ) // Expression is not allowed as static initializer workaround
$anonymous = function ( self $thisObj ) return $thisObj ;
>;
>
return $anonymous ( $this );
>
>

$a = new Foo ();
$b = new Foo ();
var_dump ( $a -> bar () === $a ); // True
var_dump ( $b -> bar () === $a ); // False
?>

You can always call protected members using the __call() method — similar to how you hack around this in Ruby using send.

class Fun
<
protected function debug ( $message )
<
echo «DEBUG: $message \n» ;
>

public function yield_something ( $callback )
<
return $callback ( «Soemthing!!» );
>

public function having_fun ()
<
$self =& $this ;
return $this -> yield_something (function( $data ) use (& $self )
<
$self -> debug ( «Doing stuff to the data» );
// do something with $data
$self -> debug ( «Finished doing stuff with the data.» );
>);
>

// Ah-Ha!
public function __call ( $method , $args = array())
<
if( is_callable (array( $this , $method )))
return call_user_func_array (array( $this , $method ), $args );
>
>

$fun = new Fun ();
echo $fun -> having_fun ();

When using anonymous functions as properties in Classes, note that there are three name scopes: one for constants, one for properties and one for methods. That means, you can use the same name for a constant, for a property and for a method at a time.

Since a property can be also an anonymous function as of PHP 5.3.0, an oddity arises when they share the same name, not meaning that there would be any conflict.

Consider the following example:

class MyClass const member = 1 ;

public function member () return «method ‘member'» ;
>

public function __construct () $this -> member = function () return «anonymous function ‘member'» ;
>;
>
>

header ( «Content-Type: text/plain» );

var_dump ( MyClass :: member ); // int(1)
var_dump ( $myObj -> member ); // object(Closure)#2 (0) <>
var_dump ( $myObj -> member ()); // string(15) «method ‘member'»
$myMember = $myObj -> member ;
var_dump ( $myMember ()); // string(27) «anonymous function ‘member'»
?>

That means, regular method invocations work like expected and like before. The anonymous function instead, must be retrieved into a variable first (just like a property) and can only then be invoked.

Источник

The Closure Class

A closure is an anonymous function, but an anonymous function is not a closure.

Читайте также:  Блочная вёрстка

An anonymous function declares without any named identifier to refer to it. A closure is an anonymous function that closes over the environment in which it was defined. This means a closure can use of variables from outside its scope (parent scope).

PHP closures and anonymous functions (including arrow functions) use the same syntax as a function, but if you inspect a PHP closure or an anonymous function (or an arrow function), you’ll find they are instances of the Closure class:

; echo get_class($anony); # Prints: Closure echo gettype($anony); # Prints: object //Arrow function $arrow = fn() => 'im an arrow func'; echo get_class($arrow); # Prints: Closure echo gettype($arrow); # Prints: object

Use keyword

Variables are not accessible inside functions unless they are declared as global :

; echo $anony('World'); # Warning: Undefined variable $hello . on line 5

In much the same way, variables from the child scope are not accessible from within the closure unless explicitly stated using the use keyword:

; echo $closure('World'); # Prints: Hello World

A closure in PHP is an anonymous (lambda) function that encapsulates its surrounding state at the time it is created. The encapsulated state exists inside the closure even when the closure lives after its original environment ceases to exist.

Example: Passing multiple parameters and use multiple outer scope variables in a closure:

Closure class

PHP introduced the Closure class in the 5.3 version. The closure class is used to represent anonymous functions. Anonymous functions, implemented in PHP 5.3, yield objects of this type. Since PHP 5.4, the Closure class got several methods that allow further control of the anonymous function after it has been created.

bindTo() method

The bind() and bindTo() methods basically duplicate the Closure with a specific bound object and class scope.

Closures have the ability to capture a context from outside of the function’s scope (using use keyword). In addition to variables, this context can also be an object’s scope. This creates a closure object that has access to the properties of the object.

  • the object to which the closure is bound
  • the class scope that it is associated with it

To access private and protected , the name of the class must be specified as the second argument:

 $closure = function () < return $this->hi; >; $getHi = $closure->bindTo(new A , 'A'); echo $getHi(); // Hello

bind() method

The bind() method has three parameters:

  • The anonymous functions to bind
  • The object to which the given anonymous function should be bound
  • The class scope that it is associated with
 $closure = function () < return $this->hi; >; $getHi = Closure::bind($closure,new A, 'A'); echo $getHi(); // Hello

Call() method

PHP 7 introduced the call method on a Closure class. The call method does not duplicate the closure, it temporarily binds the closure to the object, and calls it with any given parameters. It then returns the return value of the closure:

 $closure = function () < return $this->hi; >; $getHi = $closure->call(new A); echo $getHi; // Hello

Note: you can replace the anonymous function with the arrow function, following is the modified example:

 $closure = fn() => $this->hi; $getHi = $closure->call(new A); echo $getHi; // Hello

PHP OOP Tutorials:

Источник

Оцените статью