Usando `$ this` em uma função anônima no PHP anterior a 5.4.0

86

O manual do PHP afirma

Não é possível usar uma $thisfunção anônima antes do PHP 5.4.0

na página de funções anônimas . Mas descobri que posso fazer isso funcionar atribuindo $thisa uma variável e passando a variável para uma useinstrução na definição da função.

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

Esta é uma boa prática?
Existe uma maneira melhor de acessar $thisdentro de uma função anônima usando PHP 5.3?

movido a vapor
fonte
1
Apenas uma convenção de fórum menor - geralmente é melhor aceitar uma resposta do que editar uma pergunta para refletir sua resposta preferida. Principalmente para que as respostas ainda façam sentido para sempre, mas também, é claro, para dar crédito a uma resposta correta.
Halfer
4
Cuidado com isso $CI = $this;e $CI =& $this; não são realmente idênticos. Talvez para seus propósitos, mas eles não são os mesmos. Experimente $CI = 'bla'; var_dump($this);com as duas versões para ver a diferença.
Rudie
1
@Rudie Estou adicionando a documentação para seu comentário
steampowered
@steampowered Há um bom exemplo / artigo online em algum lugar sobre isso, mas não consegui encontrar =) Desculpe. Experimente se você não vê a diferença. É óbvio então.
Rudie

Respostas:

67

Ele falhará quando você tentar chamar um método protegido ou privado nele, porque usá-lo dessa forma conta como uma chamada externa. Não há como contornar isso no 5.3 até onde eu sei, mas com o PHP 5.4, ele funcionará conforme o esperado, pronto para uso:

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"

Ainda mais, você será capaz de alterar o que $ this aponta em tempo de execução, para funções anonymus (religação de encerramento):

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"

Efetivamente, as funções anonymus terão um método bindTo () , onde o primeiro parâmetro pode ser usado para especificar para que $ this aponta, e o segundo parâmetro controla qual deve ser o nível de visibilidade . Se você omitir o segundo parâmetro, a visibilidade será como chamar de "fora", por exemplo. apenas propriedades públicas podem ser acessadas. Observe também como funciona o bindTo, ele não modifica a função original, mas retorna uma nova .

K. Norbert
fonte
1
Marcando sua resposta correta, mas apenas para esclarecer para outros leitores: a convenção usada na pergunta funcionará para métodos públicos que utilizem o objeto que está referenciando $this.
movido a vapor
5
Métodos não públicos podem ser acessados ​​usando reflexão. Ineficiente e um pouco mau, mas funciona.
outis
7

Não confie sempre no PHP para passar objetos por referência, quando você está atribuindo uma referência a si mesmo, o comportamento não é o mesmo que na maioria das linguagens OO onde o ponteiro original é modificado.

seu exemplo:

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

deveria estar:

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

NOTA A REFERÊNCIA "&" e $ CI devem ser atribuídas após as chamadas finais serem feitas, caso contrário, você pode ter uma saída imprevisível, em PHP acessar uma referência nem sempre é o mesmo que acessar a classe original - se isso fizer sentido.

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

Christof Coetzee
fonte
6

Essa é a maneira normal de fazer.
btw, tente remover o &que deve funcionar sem isso, pois os objetos passam por ref de qualquer maneira.

Itay Moav -Malimovka
fonte
1

Isso parece certo se a sua passagem por referência for a maneira correta de fazê-lo. Se estiver usando PHP 5, você não precisa do &símbolo antes, $thispois ele sempre passará por referência independentemente.

fogo
fonte
2
O OP deve estar usando 5.3 ou superior, já que 4.x não suportava funções anônimas :-)
halfer
1

Isto é bom. Acho que você também pode fazer isso:

$CI = $this;

... visto que atribuições envolvendo objetos sempre copiarão referências, não objetos inteiros.

halfer
fonte