Каковы различия между закрытием в JS и закрытием в PHP? Они в значительной степени работают одинаково? Есть ли какие-либо оговорки, о которых следует знать при написании закрытий в PHP?
Одно из отличий заключается в том, как оба справляются с сохранением контекста, в котором выполняется анонимная функция:
// JavaScript: var a = 1; var f = function() { console.log(a); }; a = 2; f(); // will echo 2; // PHP $a = 1; $f = function() { echo $a; }; $a = 2; $f(); // will result in a "PHP Notice: Undefined variable: a in Untitled.php on line 5"
Чтобы исправить это уведомление, вам придется use
синтаксис use
:
$a = 1; $f = function() use ($a) { echo $a; }; $a = 2; $f(); // but this will echo 1 instead of 2 (like JavaScript)
Чтобы анонимная функция вела себя как-то похожий на аналог JavaScript, вам придется использовать ссылки:
$a = 1; $f = function() use (&$a) { echo $a; }; $a = 2; $f(); // will echo 2
Я думаю, что это самое яркое различие между закрытием JavaScript и PHP.
Второе отличие состоит в том, что каждое закрытие JavaScript имеет this
контекст, который означает, что вы можете использовать this
внутри самого закрытия (хотя часто бывает сложно определить, что this
самом деле означает) – текущая стабильная версия PHP (PHP 5.3) не но поддерживают $this
внутри закрытия, но будущая версия PHP (PHP 5.4) будет поддерживать $this
привязку и переупорядочивание, используя $closure->bind($this)
(дополнительную информацию см. в RFC-расширении Object ).
Третье отличие состоит в том, как оба языка обрабатывают замыкания, назначенные свойствам объекта:
// JavaScript var a = { b: function() {} }; ab(); // works // PHP $a = new stdClass(); $a->b = function() {}; $a->b(); // does not work "PHP Fatal error: Call to undefined method stdClass::b() in Untitled.php on line 4" $f = $a->b; $f(); // works though
То же самое верно, если закрытие назначается свойствам в определениях классов:
class A { public $b; public function __construct() { $this->b = function() {}; } public function c() { $this->b(); } } $a = new A(); // neither $a->b(); // nor $a->c(); // do work
Четвертое различие: JavaScript Закрытие – это полноценные объекты, в PHP они ограниченные объекты. Например, PHP Closures не может иметь собственных свойств:
$fn = function() {}; $fn->foo = 1; // -> Catchable fatal error: Closure object cannot have properties
в то время как в JavaScript вы можете:
var fn = function() {}; fn.foo = 1; fn.foo; // 1
Пятая разница: возвращенные замыкания можно сразу вызвать в Javascript:
var fn = function() { return function() { alert('Hi');}} fn()();
Не в PHP:
$fn = function() { return function() { echo('Hi');};}; $fn()(); // syntax error
Единственное, что я нашел в PHP (это абсолютно здорово и очень удобно!) – это возможность использовать их как геттеры и сеттеры в классах, которые всегда были кошмаром для достижения прежде, JavaScript можно использовать одинаково, но они оба действуют почти идентично тому, что я видел.
Я не уверен в различиях между соглашениями об именах между ними, но, поскольку @Rijk указал, что есть раздел на веб-сайте PHP, посвященный им
<?php class testing { private $foo = 'Hello '; public $bar = 'Bar'; #Act like a getter and setter! public static $readout = function ($val = null) { if (!empty($val)) { testing::$readout = $val; } return testing::$readout; } }
Они также отлично подходят для …
Зацикливание элементов с помощью контроллера, а не нового для каждого цикла на странице
Отлично подходит для предоставления аргументов функциям / классам
Что раздражает их …
Вы не можете их придумать, поскольку они просто функции …
Они работают очень точно так же. Вот еще информация о реализации PHP: http://php.net/manual/en/functions.anonymous.php
Вы можете использовать закрытие (в PHP, называемое «анонимная функция») в качестве обратного вызова:
// return array of ids return array_map( function( $a ) { return $a['item_id']; }, $items_arr );
и присвоить его переменной:
$greet = function( $string ) { echo 'Hello ' . $string; }; // note the ; ! echo $greet('Rijk'); // "Hello Rijk"
Кроме того, анонимная функция «наследует» область, в которой они были определены – так же, как реализация JS, с одним полученным : вы должны перечислить все переменные, которые вы хотите наследовать в use()
:
function normalFunction( $parameter ) { $anonymous = function() use( $parameter ) { /* ... */ }; }
и в качестве ссылки, если вы хотите изменить переменную orignal.
function normalFunction( $parameter ) { $anonymous = function() use( &$parameter ) { $parameter ++ }; $anonymous(); $parameter; // will be + 1 }