В чем разница между закрытием в JS и закрытием в PHP? Они в значительной степени работают одинаково? Есть ли какие-либо оговорки, о которых следует знать при написании закрытий в PHP?
Закрытие Javascript против закрытия PHP, какая разница?
Ответ 1
Одно из отличий заключается в том, как справляться с сохранением контекста, в котором выполняется анонимная функция:
// 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
:
$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 для получения дополнительной информации.)
Третья разница заключается в том, как оба языка относятся к закрытию, назначенным свойствам объекта:
// JavaScript
var a = {
b: function() {}
};
a.b(); // 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
Ответ 2
Единственное, что я нашел в 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;
}
}
Они также отлично подходят для...
Зацикливание элементов с помощью контроллера, а не нового для каждого цикла на странице
Отлично подходит для предоставления в качестве аргументов функций/классов
Что раздражает их...
Вы не можете их вывести, поскольку они просто функции...
Ответ 3
Они работают очень точно так же. Здесь дополнительная информация о реализации 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
}