經過幾個栗子認識 PHP 閉包

<!-- TOC -->php

<!-- /TOC -->閉包

有收穫的話請加顆小星星,沒有收穫的話能夠 反對 沒有幫助 舉報三連函數

  • 示例代碼
  • 本文地址
  • 本人能力有限,如遇到什麼不對的地方還望指出修正,謝謝
  • 全部栗子的輸出都使用symfony/var-dumpe美化了

匿名函數(Anonymous functions),也叫閉包函數(closures),容許 臨時建立一個沒有指定名稱的函數。最常常用做回調函數(callback)參數的值。固然,也有其它應用的狀況。測試

匿名函數目前是經過 Closure 類來實現的。ui

1、栗子1 用做於回調

$rs = preg_replace_callback('/-([a-z])/', function ($match) {
    return strtoupper($match[1]);
}, 'hello-world');

dump($rs); // "helloWorld"

2、栗子2 用做於變量賦值

$greet = function ($name) {
    dump($name);
};

dump($greet instanceof Closure); // true
$greet('PHP'); // "PHP"

3、栗子3 從父做用域繼承變量

$message = 'hello';
$example = function () use ($message) {
    dump($message);
};
dump($example instanceof Closure); // true
$example(); // "hello"

4、栗子4的前提條件,簡單理解call_user_func_array()call_user_func()方法

1. call_user_func — 把第一個參數做爲回調函數調用

function call_user_func ($function, ...$parameter) {}this

該方法接收多個參數,第一個就是回調函數,能夠是普通函數,也能夠是閉包函數,後面的多個參數都是做爲函數回調使用spa

$rs = call_user_func(function (...$params) {
    return func_get_args();
}, 1, 2, 3);
dump($rs); // [1,2,3]

2. call_user_func_array — 調用回調函數,並把一個數組參數做爲回調函數的參數

function call_user_func_array ($function, array $param_arr) {}

該方法接收2個參數,第一個就是回調函數,能夠是普通函數,也能夠是閉包函數,後面的數組參數都是做爲函數回調使用

$rs = call_user_func_array(function (array $params) {
    return func_get_args();
}, [1, 2, 3]);
dump($rs); // [1,2,3]

5、栗子4 綁定閉包在指定對象

樓主看法是將方法綁定到指定類上,使得方法也可使用類的屬性和方法,很是適合配合__call()魔術方法和call_user_func_array方法一塊兒使用

1. Closure::bindTo — 複製當前閉包對象,綁定指定的$this對象和類做用域。

function bindTo($newthis, $newscope = 'static') { }

<?php
namespace PHP\Demo\Closure;

class ClosureBindTo
{
    public function __call($name, $arguments)
    {
        if (count($arguments) > 1 && $arguments[0] instanceof \Closure) {
            return call_user_func_array($arguments[0]->bindTo($this), array_slice($arguments, 1));
        }
        throw new \InvalidArgumentException("沒有這個方法");
    }
}

// 測試
public function testClosureBindTo()
{
    $obj = new ClosureBindTo();
    $this->assertEquals(2, $obj->add(function (array $params) {
        return ++$params[0];
    }, [1]));

    // 測試同一個實例
    $newObj = $obj->test(function (array $params){
        return $this;
    }, [1]);
    $this->assertTrue($newObj instanceof $obj);
}

2. Closure::bind — 複製一個閉包,綁定指定的$this對象和類做用域。

static function bind(Closure $closure, $newthis, $newscope = 'static') { }

bind函數是bindTo的靜態表示

<?php
namespace PHP\Demo\Closure;

class ClosureBind
{
    private $methods = [];

    public function addMethod(string $name, \Closure $callback)
    {
        if (!is_callable($callback)) {
            throw new \InvalidArgumentException("第二個參數有誤");
        }
        $this->methods[$name] = \Closure::bind($callback, $this, get_class());
    }

    public function __call(string $name, array $arguments)
    {
        if (isset($this->methods[$name])) {
            return call_user_func_array($this->methods[$name], $arguments);
        }

        throw new \RuntimeException("不存在方法[{$name}]");
    }
}

// 測試
public function testClosureBind()
{
    $obj = new ClosureBind();
    $obj->addMethod('add', function (array $params) {
        return ++$params[0];
    });
    $this->assertEquals(2, $obj->add([1]));

    // 測試同一個實例
    $obj->addMethod('test', function (array $params) {
        return $this;
    });
    $this->assertTrue($obj->test([1]) instanceof $obj);
}

6、參考資料

相關文章
相關標籤/搜索