Закрытия Javascript против закрытий PHP, в чем разница? - PullRequest
50 голосов
/ 14 сентября 2011

Каковы различия между замыканиями в JS и замыканиями в PHP?Они в значительной степени работают одинаково?Есть ли какие-то предостережения, о которых следует знать при написании замыканий в PHP?

Ответы [ 3 ]

116 голосов
/ 14 сентября 2011

Разница в том, как оба справляются с сохранением контекста, в котором выполняется анонимная функция:

// 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-замыкания не могут иметь свои собственные свойства:

$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
4 голосов
/ 14 сентября 2011

Единственное, что я нашел в 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;
        }
    }

Они также отлично подходят для ...

Циклический просмотр элементов с помощью контроллера, а не нового цикла for / each на странице

Отлично подходит для предоставления в качестве аргументов для функций / классов

Что их раздражает, так это ...

Вы не можете вводить их по типу, так как онипросто функции ...

2 голосов
/ 14 сентября 2011

Они в основном работают одинаково.Вот дополнительная информация о реализации 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 ) { /* ... */ };
}

и в качестве ссылки, если вы хотите изменить оригинальную переменную.

function normalFunction( $parameter ) {
    $anonymous = function() use( &$parameter ) { $parameter ++ };
    $anonymous();
    $parameter; // will be + 1
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...