Використання `$ 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
Просто незначна конвенція форуму - зазвичай краще прийняти відповідь, ніж редагувати питання, щоб відобразити бажану відповідь. Головним чином це для того, щоб відповіді все ще мали сенс постійно, але також, звичайно, щоб віддати належне правильній відповіді.
половинка

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.
парогенератор

5
До публічних методів можна отримати доступ за допомогою рефлексії. Неефективно і трохи зло, але це працює.
вихід

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

Це нормальний спосіб, яким це було зроблено.
До речі, спробуйте видалити &це повинно працювати без цього, оскільки об'єкти проходять повз ref будь-яким способом.


1

Це здається добре, якщо ваше передавання за посиланням - це правильний спосіб це зробити. Якщо ви використовуєте PHP 5, вам &раніше символ не потрібен, $thisоскільки він завжди буде передаватися за посиланням, незалежно.


2
OP повинен використовувати 5.3 або більше, оскільки 4.x не підтримував анонімних функцій :-)
halfer

1

Це добре. Я повинен думати, що ви можете зробити це також:

$CI = $this;

... оскільки призначення за участю об’єктів завжди копіюватимуть посилання, а не цілі об’єкти.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.