Rumah > Artikel > pembangunan bahagian belakang > Menganalisis fungsi penutupan PHP dan kaedah kelas Course
0x00 Prakata
Penutupan merujuk kepada fungsi yang merangkum keadaan sekeliling apabila ia dicipta. Walaupun persekitaran di mana penutupan terletak tidak lagi wujud, keadaan yang terkandung dalam penutupan masih wujud.
Semua penutupan dalam PHP adalah objek yang dibuat oleh kelas Clourse, yang bermaksud penutupan tidak berbeza daripada objek PHP lain. Objek mesti mempunyai kaedah dan sifatnya Artikel ini akan meringkaskan penggunaan asas penutupan dalam PHP dan peranan kaedah kelas Clourse. [Disyorkan: Tutorial video PHP]
0x01 Penggunaan asas penutupan
Mari kita lihat penggunaan penutupan yang paling asas:
<?php $hello = function ($word) { return 'hello ' . $word; }; echo $hello('world'); // 输出 hello world
Hei, perasaan paling intuitif bagi kod ini ialah untuk menetapkan fungsi kepada pembolehubah $hello dan kemudian memanggilnya terus melalui $hello. Tetapi penutupan ini tidak mewarisi pembolehubah daripada skop induk (iaitu, ia merangkumi keadaan sekeliling Kita boleh mewarisi pembolehubah daripada skop induk penutupan melalui kata kunci penggunaan). Contohnya adalah seperti berikut:
<?php $name = 'panda'; $hello = function () use ($name) { return 'hello ' . $name; }; echo $hello(); // 输出 hello panda
Bermula dari PHP 7.1, penggunaan tidak boleh lulus dalam pembolehubah sedemikian: superglobals, $this atau mempunyai nama yang sama sebagai parameter.
Selain itu, apabila menggunakan kata kunci penggunaan, pembolehubah skop induk dihantar ke penutupan mengikut nilai. Maksudnya, sebaik sahaja penutupan dibuat, walaupun pembolehubah luaran diubah suai, ia tidak akan menjejaskan nilai yang dihantar ke penutupan (iaitu, walaupun persekitaran di mana penutupan terletak tidak lagi wujud, keadaan terkandung dalam penutupan masih wujud). Contohnya adalah seperti berikut:
<?php $name = 'panda'; $hello = function () use ($name) { return 'hello ' . $name; }; $name = 'cat'; echo $hello(); // 输出 hello panda
Melalukan rujukan kepada pembolehubah membenarkan penutupan untuk mengubah suai nilai pembolehubah luaran Contohnya adalah seperti berikut:
<?php $name = 'panda'; $changeName = function () use (&$name) { $name = 'cat'; }; $changeName(); echo $name; // 输出 cat
Nota: Apabila menghantar objek dalam PHP, lalai adalah menggunakan rujukan memerlukan perhatian khusus apabila mengendalikan objek yang diluluskan oleh penggunaan dalam penutupan. Contohnya adalah seperti berikut:
<?php class Dog { public $name = 'Wang Cai'; } $dog = new Dog(); $changeName = function () use ($dog) { $dog->name = 'Lai Fu'; }; $changeName(); echo $dog->name; // 输出 Lai Fu
Kelas penutupan 0x02
Bukti bahawa penutupan hanyalah objek kelas Penutupan
<?php $clourse = function () { echo 'hello clourse'; }; if (is_object($clourse)) { echo get_class($clourse); } // 输出 Closure
Perkara di atas kod akan mengeluarkan bukti Penutupan Penutupan hanyalah objek kelas Penutupan biasa.
Ringkasan kelas tutup
Kita boleh melihat maklumat berkaitan kelas penutupan daripada manual rasmi PHP Berikut ialah ringkasan kelas Clourse yang saya lihat dokumentasi tempatan PhpStorm.
/** * Class used to represent anonymous functions. * <p>Anonymous functions, implemented in PHP 5.3, yield objects of this type. * This fact used to be considered an implementation detail, but it can now be relied upon. * Starting with PHP 5.4, this class has methods that allow further control of the anonymous function after it has been created. * <p>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. * @link http://www.php.net/manual/en/class.closure.php */ final class Closure { /** * This method exists only to disallow instantiation of the Closure class. * Objects of this class are created in the fashion described on the anonymous functions page. * @link http://www.php.net/manual/en/closure.construct.php */ private function __construct() { } /** * This is for consistency with other classes that implement calling magic, * as this method is not used for calling the function. * @param mixed $_ [optional] * @return mixed * @link http://www.php.net/manual/en/class.closure.php */ public function __invoke(...$_) { } /** * Duplicates the closure with a new bound object and class scope * @link http://www.php.net/manual/en/closure.bindto.php * @param object $newthis The object to which the given anonymous function should be bound, or NULL for the closure to be unbound. * @param mixed $newscope The class scope to which associate the closure is to be associated, or 'static' to keep the current one. * If an object is given, the type of the object will be used instead. * This determines the visibility of protected and private methods of the bound object. * @return Closure Returns the newly created Closure object or FALSE on failure */ function bindTo($newthis, $newscope = 'static') { } /** * This method is a static version of Closure::bindTo(). * See the documentation of that method for more information. * @static * @link http://www.php.net/manual/en/closure.bind.php * @param Closure $closure The anonymous functions to bind. * @param object $newthis The object to which the given anonymous function should be bound, or NULL for the closure to be unbound. * @param mixed $newscope The class scope to which associate the closure is to be associated, or 'static' to keep the current one. * If an object is given, the type of the object will be used instead. * This determines the visibility of protected and private methods of the bound object. * @return Closure Returns the newly created Closure object or FALSE on failure */ static function bind(Closure $closure, $newthis, $newscope = 'static') { } /** * Temporarily binds the closure to newthis, and calls it with any given parameters. * @link http://php.net/manual/en/closure.call.php * @param object $newThis The object to bind the closure to for the duration of the call. * @param mixed $parameters [optional] Zero or more parameters, which will be given as parameters to the closure. * @return mixed * @since 7.0 */ function call ($newThis, ...$parameters) {} /** * @param callable $callable * @return Closure * @since 7.1 */ public static function fromCallable (callable $callable) {} }
Pertama sekali, kelas Penutupan ialah kelas akhir, yang bermaksud bahawa ia tidak boleh diwarisi Kedua, pembinanya __konstruk ditetapkan kepada persendirian, yang bermaksud objek penutupan tidak boleh dijadikan instantiated melalui. kata kunci baru. Kedua-dua Titik ini menjamin bahawa penutupan hanya boleh dibuat melalui fungsi sintaks (...) use(...) {...}.
Mengapa penutupan boleh dilaksanakan sebagai fungsi?
Daripada ringkasan kelas di atas, kita dapat melihat bahawa kelas Clourse melaksanakan kaedah __invoke, yang dijelaskan dalam manual PHP rasmi seperti berikut:
Apabila cuba memanggil fungsi Apabila objek dipanggil, kaedah __invoke() dipanggil secara automatik.
Inilah sebabnya penutupan boleh dilaksanakan sebagai fungsi.
Ikat objek $this dan skop kelas yang ditentukan
Dalam rangka kerja yang membenarkan penggunaan penghalaan penutupan (seperti: Slim), kita dapat melihat tulisan berikut:
$app->get('/test', function () { echo $this->request->getMethod(); });
Bolehkah saya menggunakan $ini dalam penutupan? Objek yang $ini tunjuk?
Fungsi mengikat $this dan skop kelas boleh direalisasikan melalui kaedah bindTo dan bind Contohnya seperti berikut:
<?php class Pandas { public $num = 1; } $pandas = new Pandas(); $add = function () { echo ++$this->num . PHP_EOL; }; $newAdd1 = $add->bindTo($pandas); $newAdd1(); // 输出 2 $newAdd2 = Closure::bind($add, $pandas); $newAdd2(); // 输出 3
Contoh di atas mengikat objek yang ditentukan sebagai penutup. . daripada $this, tetapi kami tidak menyatakan skop kelas. Jadi jika anda menulis semula harta $num kelas Pandas kepada protected atau private, ralat maut akan dilemparkan!
Fatal error: Uncaught Error: Cannot access protected property Pandas::$num
Apabila kita perlu mengakses sifat bukan awam atau kaedah objek terikat, kita perlu menentukan skop kelas contohnya seperti berikut:
<?php class Pandas { protected $num = 1; } $pandas = new Pandas(); $add = function () { echo ++$this->num . PHP_EOL; }; $newAdd1 = $add->bindTo($pandas, $pandas); $newAdd1(); // 输出 2 $newAdd2 = Closure::bind($add, $pandas, 'Pandas'); $newAdd2(); // 输出 3
Di sini kita lihat bahawa kedua-dua kaedah bindTo dan bind Jika parameter $newscope ditentukan, parameter $newscope lalai kepada statik, yang bermaksud skop kelas tidak akan diubah. Parameter $newscope menerima nama kelas atau objek dan menukar skop kelas penutupan kepada skop kelas yang ditentukan Pada masa ini, sifat $num kelas Pandas boleh diakses melalui penutupan.
Ikat $ini dan skop kelas sekali dan jalankan (PHP7)
kaedah bindTo dan bind dilaksanakan setiap kali objek baharu dan skop kelas ditentukan Untuk menyalin penutupan asal dan kemudian mengembalikan penutupan baharu, ia menjadi menyusahkan apabila objek terikat perlu diubah suai beberapa kali, jadi PHP7 menyediakan panggilan kaedah baharu, yang boleh mengikat penutupan sementara pada objek (skop kelas juga diubah suai kepada kelas kepunyaan objek) dan dilaksanakan. Contohnya adalah seperti berikut:
<?php class Pandas { protected $num = 1; } $pandas = new Pandas(); $add = function ($num) { $this->num += $num; echo $this->num . PHP_EOL; }; $add->call($pandas, 5); // 输出 6
Boleh dipanggil ditukar kepada penutupan (PHP7.1)
Dalam PHP7.1, kelas Penutupan mempunyai kaedah fromCallable yang boleh tukar nilai jenis boleh panggil Tukar kepada penutupan, contohnya adalah seperti berikut:
<?php class Foo { protected $num = 1; public static function hello(string $bar) { echo 'hello ' . $bar; } } $hello = Closure::fromCallable(['Foo', 'hello']); $hello('world');
Cara penulisan ini agak keren Lagipun, membuat panggilan melalui penutupan adalah lebih menyeronokkan daripada memanggil dengan fungsi call_user_func^_^.
0x03 Ringkasan
Untuk kandungan yang lebih berkaitan, sila lihat kelas Penutupan dan fungsi tanpa nama Kerana versi Cina kelas Penutupan dalam manual rasmi PHP belum ada dikemas kini, tiada kaedah panggilan dan daripada Boleh Dipanggil Untuk kandungan, saya mengesyorkan semua orang membaca versi Bahasa Inggeris (ㄒoㄒ).
Atas ialah kandungan terperinci Menganalisis fungsi penutupan PHP dan kaedah kelas Course. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!