Использование `$ this` в анонимной функции в PHP до 5.4.0


86

В руководстве по PHP указано

Невозможно использовать $thisанонимную функцию до PHP 5.4.0

на странице анонимных функций . Но я обнаружил, что могу заставить его работать, присвоив $thisпеременной и передав переменную в useоператор в определении функции.

$CI = $this;
$callback = function () use ($CI) {
    $CI->public_method();
};

Это хорошая практика?
Есть ли лучший способ доступа $thisк анонимной функции с помощью PHP 5.3?


1
Просто небольшое соглашение форума - обычно лучше принять ответ, чем редактировать вопрос, чтобы отразить ваш предпочтительный ответ. В основном это делается для того, чтобы ответы имели смысл на всю жизнь, но также, конечно, чтобы отдать должное правильному ответу.
Halfer 05

4
Остерегайтесь этого, $CI = $this;и на самом деле $CI =& $this; они не идентичны. Может быть, для ваших целей, но они не такие. Попробуйте использовать $CI = 'bla'; var_dump($this);обе версии, чтобы увидеть разницу.
Руди

1
@Rudie Я добавляю документацию для вашего комментария
Steampowered

@steampowered В Интернете есть хороший пример / статья об этом, но я не смог ее найти =) Извините. Просто попробуйте, если не видите разницы. Тогда это очевидно.
Руди

Ответы:


67

Он потерпит неудачу, когда вы попытаетесь вызвать на нем защищенный или частный метод, потому что его использование таким образом считается вызовом извне. Насколько я знаю, в версии 5.3 нет способа обойти это, но с выходом PHP 5.4 он будет работать, как ожидалось, из коробки:

class Hello {

    private $message = "Hello world\n";

    public function createClosure() {
        return function() {
            echo $this->message;
        };
    }

}
$hello = new Hello();
$helloPrinter = $hello->createClosure();
$helloPrinter(); // outputs "Hello world"

Более того, вы сможете изменить то, на что указывает $ this во время выполнения, для анонимных функций (повторная привязка закрытия):

class Hello {

    private $message = "Hello world\n";

    public function createClosure() {
        return function() {
            echo $this->message;
        };
    }

}

class Bye {

    private $message = "Bye world\n";

}

$hello = new Hello();
$helloPrinter = $hello->createClosure();

$bye = new Bye();
$byePrinter = $helloPrinter->bindTo($bye, $bye);
$byePrinter(); // outputs "Bye world"

Фактически, анонимные функции будут иметь метод bindTo () , где первый параметр может использоваться, чтобы указать, на что указывает $ this, а второй параметр контролирует, каким должен быть уровень видимости . Если вы опустите второй параметр, видимость будет похожа на вызов "извне", например. доступны только общедоступные свойства. Также обратите внимание на то, как работает bindTo: он не изменяет исходную функцию, а возвращает новую .


1
Отметьте свой ответ правильным, но просто для пояснения для других читателей: соглашение, используемое в вопросе, будет работать для общедоступных методов, использующих объект, на который ссылается $this.
Steampowered

5
Доступ к непубличным методам можно получить с помощью отражения. Неэффективно и немного злобно, но работает.
outis

7

Не всегда полагайтесь на PHP для передачи объектов по ссылке, когда вы назначаете ссылку, поведение не такое, как в большинстве языков OO, где изменяется исходный указатель.

ваш пример:

$CI = $this;
$callback = function () use ($CI) {
$CI->public_method();
};

должно быть:

$CI = $this;
$callback = function () use (&$CI) {
$CI->public_method();
};

ПРИМЕЧАНИЕ. ССЫЛКА "&" и $ CI должны быть назначены после того, как были выполнены окончательные вызовы, иначе вы можете получить непредсказуемый результат, в PHP доступ к ссылке не всегда совпадает с доступом к исходному классу - если это имеет смысл.

http://php.net/manual/en/language.references.pass.php


6

Это нормальный способ.
Кстати, попробуйте удалить, &он должен работать без этого, поскольку объекты проходят по ссылке в любом случае.


1

Это кажется нормальным, если вы переходите по ссылке, это правильный способ сделать это. Если вы используете PHP 5, вам не нужен &символ раньше, $thisпоскольку он всегда будет передаваться по ссылке независимо.


2
OP должен использовать
версию

1

Это отлично. Думаю, вы тоже можете это сделать:

$CI = $this;

... поскольку присваивания, включающие объекты, всегда копируют ссылки, а не целые объекты.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.