美文网首页简书Web开发PHP经验分享PHP实战
PHP新特性之闭包、匿名函数

PHP新特性之闭包、匿名函数

作者: 萧潇在jianshu | 来源:发表于2017-07-03 21:44 被阅读81次

    闭包

    闭包是什么?

    1).闭包和匿名函数在PHP5.3中被引入。
    2).闭包是指在创建时封装函数周围状态的函数,即使闭包所在的环境不存在了,闭包封装的状态依然存在,这一点和Javascript的闭包特性很相似。
    3).匿名函数就是没有名称的函数,匿名函数可以赋值给变量,还可以像其他任何PHP对象一样传递。可以将匿名函数和闭包视作相同的概念。
    4).需要注意的是闭包使用的语法和普通函数相同,但是他其实是伪装成函数的对象,是Closure类的实例。闭包和字符串或整数一样,是一等值类型。

    创建闭包
    $closure = function ($name) {
      return sprintf('hello %s', $name);
    };
    
    echo $closure('Josh');
    

    我们之所以可以调用$closure变量,是因为这个变量的值是一个闭包,而且闭包对象实现了__invoke()魔术方法,只要后面跟着(),PHP就会查找__invoke()方法。这里简单解释下这个魔术方法:

    class testClass
    {
        public function __invoke
        {
            print "hello world";
        }
    }
    $n = new testClass;
    $n();
    

    PHP自从5.3版以来就新增了一个叫做__invoke()的魔术方法,使用该方法就可以在创建实例后,直接调用对象。

    何时使用?

    我们通常把PHP闭包当做函数和方法的回调使用。很多PHP函数都会用到回调函数,例如array_map()preg_replace_callback()

    $numbersPlusOne = array_map(function($number) {
        return $number + 1;
    }, [1, 2, 3]);
    
    如何理解附加状态?

    1).注意PHP闭包不会真的像JS一样自动封装应用的状态,在PHP中必须调用闭包对象的bindTo方法或者使用use关键字,把状态附加到PHP闭包上。来看一个例子

    function enclosePerson($name)
    {
        return function ($doCommand) use ($name) {
            return sprintf('%s , %s', $name, $doCommand);
       };
    }
    //把字符串“Clay”封装在闭包中
    $clay = enclosePerson('Clay');
    //传入参数,调用闭包
    echo $clay('get me sweat tea!'); // Clay, get me sweat tea!
    

    在这个例子中,函数enclosePerson()有一个$name参数,这个函数返回一个闭包对象,这个闭包封装了$name参数,即便返回的对象跳出了enclosePerson()函数的作用域,它也会记住$name参数的值,因为$name变量仍然在闭包中。
    2).使用use关键字可以把多个关键字传入闭包,此时要想像PHP函数或方法的参数一样,使用逗号分割多个参数。
    3).PHP闭包仍然是对象,可以使用$this关键字获取闭包的内部状态。闭包的默认状态里面有一个__invoke()魔术方法和bindTo()方法。
    4).bindTo()方法为闭包增加了一些有趣的东西。我们可以使用这个方法把Closure对象内部状态绑定到其他对象上。bindTo()方法的第二个参数可以指定绑定闭包的那个对象所属的PHP类,这样我们就可以访问这个类的受保护和私有的成员变量。看下面的代码示例:

    class App
    {
        protected $route = array();
        protected $responseStatus = '200 OK';
        protected $responseContentType = 'text/html';
        protected $responseBody = 'Hello world';
    
        public function addRoute($routePath, $routeCallback)
        {
            $this->routes[$routePath] = $routeCallback->bindTo($this, __CLASS__);
        }
    
        public function dispatch($currentPath)
        {
            foreach($this->routes as $routePath => $callback) {
                if ($routePath === $currentPath) {
                     $callback();
                }
            }
            header('HTTP/1.1' . $this->responseStatus);
            header('Content-type: ' . $this->responseContentType);
            header('Content-length: ' . mb_strlen($this->responseBody));
            echo $this->responseBody;
        }
    }
    

    我们把路由回调绑定到了当前的App实例上,这样就可以在回调函数中处理App实例的状态了。

    $app = new App();
    $app->addRoute('/users/xiaoxiao', function () {
        $this->responseContentType = 'application/json;charset=utf8';
        $this->responseBody = '{"name" : "xiaoxiao"}';
    });
    $app->dispatch('/users/xiaoxiao');
    

    专题系列

    PHP专题系列目录地址:https://github.com/xx19941215/webBlog
    PHP专题系列预计写二十篇左右,主要总结我们日常PHP开发中容易忽略的基础知识和现代PHP开发中关于规范、部署、优化的一些实战性建议,同时还有对Javascript语言特点的深入研究。

    相关文章

      网友评论

        本文标题:PHP新特性之闭包、匿名函数

        本文链接:https://www.haomeiwen.com/subject/mzmzcxtx.html