Anonymous functions

Anonymous functions, also called closure functions, are simply “functions without a name”, and the general function structure, but the function name and the need to add a semicolon at the end; .

Note: Closures and anonymous functions are technically different concepts, but PHP treats them as the same concept.

$func = function()
{
    echo 'Hello World' . PHP_EOL;
};
$func(a);Copy the code

Anonymous functions are distinguished from ordinary functions by:

  • Anonymous functions can also be used as values of variables.
  • Anonymous functions can inherit variables from a parent scope, which is the function that defines the closure (not necessarily the function that calls it).
$message = 'hello';
$example = function () use ($message) {
    return $message;
};
$message = 'world';
echo $example(a); Output: hello!Copy the code

Note: Variables must be passed in using the use keyword, as described in the official documentation.

The closure class

To define a Closure function, we simply instantiate a Closure object:

$func = function()
{
    echo 'hello world' . PHP_EOL;
};
var_dump($func); Output: the object (Closure)# 1 (0) {
}Copy the code

Class summary:

Closure {
     __construct ( void )
     public static Closure bind ( Closure $closure , object $newthis [, mixed $newscope = 'static' ] )
     public Closure bindTo ( object $newthis [, mixed $newscope = 'static'])}Copy the code

In addition to the above methods, closures also implement an __invoke() magic method, which is automatically called when you try to call an object as a function.

BindTo method

Let’s look at the bindTo method, which allows us to bind the closure’s internal state to other objects. The second argument to the bindTo method is particularly important here. It specifies the PHP class to which the object bound to the closure belongs, so that the closure can access protected and private member variables in the object bound to the closure elsewhere.

You’ll notice that PHP frameworks often use the bindTo method to map routing urls to anonymous callbacks. The framework binds anonymous callbacks to application objects so that important application objects can be referenced in anonymous functions using the $this keyword:

class App {
    protected $routes = [];
    protected $responseStatus = '200 OK';
    protected $responseContentType = 'text/html';
    protected $responseBody = 'Hello World';

    public function addRoute($path.$callback) {
        $this->routes[$path] = $callback->bindTo($this, __CLASS__);
    }

    public function dispatch($path) {
        foreach ($this->routes as $routePath= >$callback) {
            if( $routePath= = =$path) {
                $callback(a); } } header('HTTP / 1.1' . $this->responseStatus);
        header('Content-Type: ' . $this->responseContentType);
        header('Content-Length: ' . mb_strlen($this->responseBody));
        echo $this->responseBody; }}Copy the code

The addRoute method takes a routing path and a routing callback, and the Dispatch method takes the path of the current HTTP request and calls the routing callback. Line 9 is the highlight, where we bind the route callback to the current App instance. This handles the state of the App instance in the callback function:

$app = new App();
$app- > addRoute ('/user ',function() {$this- > responseContentType = 'application/json; Charset = utf8 ";$this->responseBody = 'Hello world';
});
$app->dispatch('/user');Copy the code

The IoC container

Anonymous functions can inherit variables from a parent scope, which is the function that defines the closure (not necessarily the function that calls it).

Using this feature, we can implement a simple inversion of control IoC container:

class Container
{
    protected static $bindings;
 
    public static function bind($abstract, Closure $concrete)
    {
        static::$bindings[$abstract] = $concrete;
    }
 
    public static function make($abstract)
    {
        return call_user_func(static::$bindings[$abstract]);
    }
}
 
class talk
{
    public function greet($target)
    {
        echo 'Hello ' . $target->getName();
    }
}

class A
{
    public function getName()
    {
        return 'World'; } // Create an instance of the talk class$talk= new talk(); // Bind class A to A Container named foo Container::bind('foo'.function() {
    returnnew A; }); // Fetch the instance from the container$talk->greet(Container::make('foo')); // Hello WorldCopy the code

In the example above, the instance is created only when it is retrieved through the make method, which allows us to implement the container.

Closures and bindTo methods are also widely used in Laravel framework, which can realize more advanced features such as event triggering.

I hope the above content can help you. Many PHPer will encounter some problems and bottlenecks when they are advanced, and they have no sense of direction when writing too many business codes. I have sorted out some information, including but not limited to: Distributed architecture, high scalability, high performance, high concurrency, server performance tuning, TP6, Laravel, YII2, Redis, Swoft, Kafka, Mysql optimization, shell scripting, Docker, microservices, Nginx, etc. Many knowledge points are free to share with you