那一天,人们终于回想起了被BUG支配的恐惧
Toggle navigation
Home
AboutMe
Links
Archives
Tags
PHP匿名函数,闭包
2016-04-30 18:11:32
620
0
0
weibo-007
#在PHP中应用回调例子 如果对js非常熟悉的话,一定对匿名函数,回调等概念不陌生 ``` $("#username").clcik(function(){ //code $getJSON('/data.php', {name:name}, function(){ //远程获取数据 }); }); ``` 相信写js的人对上面的代码一定不陌生,同样,PHP之道的发起人写的`slim`框架,也在大量使用类似的语法,比如下面一段slim的代码 ``` $app->get('/', function ($request, $response, $args) { return $response->write("Hello " . $args['name']); }); ``` 是不是写php跟写jQuery似的,非常有意思,Slim的作者是PHP和JavaScript程序员,同时也是《PHP The Right Way》的作者,相信js工程师也一定非常喜欢这样的语法。 #PHP创建闭包 注意,在PHP中,匿名函数(Anonymous functions),也叫闭包函数(closures),允许 临时创建一个没有指定名称的函数。最经常用作回调函数(callback)参数的值。当然,也有其它应用的情况。比如官网一个闭包函数的例子 ``` <?php echo preg_replace_callback('~-([a-z])~', function ($match) { return strtoupper($match[1]); }, 'hello-world'); // 输出 helloWorld ``` 闭包函数也可以作为变量的值来使用。PHP 会自动把此种表达式转换成内置类 Closure 的对象实例。把一个 closure 对象赋值给一个`变量的方式`与普通变量赋值的语法是一样的,最后也要加上分号: ``` <?php $add = function($a, $b){ return $a + $b; }; echo $add(3,4);//输出7 ``` 注意,闭包函数构建了自己个一个作用域,如果需要使用父级作用域中的变量,必须使用`use`关键字 ``` <?php $message = 'hello'; $say1 = function(){ echo $message; }; $say2 = function() use ($message){ echo $message; } $say1();//PHP Notice: Undefined variable: message $say2();//hello ``` #闭包的本质 闭包和匿名函数其实就是伪装成函数的对象,如果审查PHP闭包或者匿名函数,你会发现它就是Closure类的实例,比如创建这个闭包 ``` <?php $add = function($a, $b){ return $a + $b; }; echo $add(3,4);//输出7 ``` 闭包的情况是: 1. 创建一个闭包对象,这个对象继承Closure类 2. 实现Closure类中的__invoke()方法 2. 把闭包赋值给$add对象 3. 只要变量名后面有(),就立马调用__invoke()方法 比如下面这个例子证明闭包就是Closure类的实现 ``` <?php $add = function($a, $b){ return $a + $b; }; var_dump($add instanceof Closure);//输出true echo $add->__invoke(3,4);//输出7 ``` 或者再看一个例子,()会触发类的__invoke()方法 ``` <?php class Func{ function __invoke(){ echo 8888; } } $func = new Func(); $func();//输出8888 ``` #闭包实现路由回调 前面说到闭包有一个__invoke()魔术方法,但是,闭包还有一个方法,叫bindTo().这个方法可以吧Closure对象的内部状态绑定到其他对象上。bindTo方法的第二个参数很重要,作用是指定绑定闭包的那个对象所属的PHP类。基于这一点,我们可以使用bindTo()方法把路由URL映射到匿名回调函数上,框架会把匿名函数绑定到应用对象上,这么做之后就可以在匿名函数中使用$this关键字引用重要的应用对象 ``` <?php class App{ protected $routes = array(); protected $responseStatus = 200; protected $responseContentType = 'text/html'; protected $responseBody = ''; public function addRoute($path, $call){ /** * 第一个参数给匿名函数的一个对象,或者 NULL 来取消绑定。这里表示当前对象App * 第二个参数关联到匿名函数的类作用域,这会决定绑定的对象的 保护、私有成员 方法的可见性,这一项保持可以访问protected属性 */ $this->routes[$path] = $call -> bindTo($this, __CLASS__); } public function dispatch($curr_path){ foreach($this->routes as $path => $call){ if($path == $curr_path){ //执行回调函数 $call(); } } header('HTTP/1.1'. $this->responseStatus); header('Content-type: '. $this->responseContentType); header('Content-length: '. mb_strlen($this->responseBody)); echo $this->responseBody; } } $app = new App(); $app -> addRoute('/', function(){ //由于这个匿名函数关联到了App类,这里的$this指向App这个实例 $this->responseContentType = 'application/json'; $this->responseBody = '{"name":"yongxiong"}'; }); $app -> dispatch('/'); ``` 测试这个路由App,使用PHP启动服务器 ``` php -S localhost:9000 ``` 可以看到以下访问结果 <img src="http://leanote.com/api/file/getImage?fileId=56f67d7fab644122de000c56" width="500">
Pre:
什么是SPL
Next:
Memcache初探
0
likes
620
Weibo
Wechat
Tencent Weibo
QQ Zone
RenRen
Submit
Sign in
to leave a comment.
No Leanote account?
Sign up now.
0
comments
More...
Table of content
No Leanote account? Sign up now.