PHP-эквивалент привязки JavaScript
Во-первых, извините за мой английский, я не являюсь носителем языка, и извините, если это выглядит грубо, это первый раз, когда я публикую на этом сайте. Я думаю, что моя проблема довольно проста. Допустим, у нас есть:
class A {
function foo() {
function bar ($arg){
echo $this->baz, $arg;
}
bar("world !");
}
protected $baz = "Hello ";
}
$qux = new A;
$qux->foo();
В этом примере "$this" явно не относится к моему объекту "$qux".
Как мне сделать, чтобы он соответствовал "$qux"?
Как может быть в JavaScript : bar.bind(this, "world !")
4 answers
PHP не имеет вложенных функций, поэтому в вашем примере bar
по сути является глобальным. Вы можете достичь того, чего хотите, используя замыкания (=анонимные функции), которые поддерживают привязку начиная с PHP 5.4:
class A {
function foo() {
$bar = function($arg) {
echo $this->baz, $arg;
};
$bar->bindTo($this);
$bar("world !");
}
protected $baz = "Hello ";
}
$qux = new A;
$qux->foo();
UPD: однако bindTo($this)
не имеет особого смысла, потому что замыкания автоматически наследуют this
из контекста (опять же, в 5.4). Таким образом, ваш пример может быть простым:
function foo() {
$bar = function($arg) {
echo $this->baz, $arg;
};
$bar("world !");
}
UPD2: для php 5.3 - это, похоже, возможно только с таким уродливым взломом, как это:
class A {
function foo() {
$me = (object) get_object_vars($this);
$bar = function($arg) use($me) {
echo $me->baz, $arg;
};
$bar("world !");
}
protected $baz = "Hello ";
}
Здесь get_object_vars()
используется для "публикации" защищенных/частных свойств, чтобы сделать их доступными в рамках закрытия.
На самом деле, $this
действительно ссылается на $qux
, когда вызывается в этом контексте.
Вы не можете использовать $this
в контекстах, отличных от метода объекта, поэтому, если вы взяли что-то вроде этого:
function test() {
echo $this->baz;
}
Это не сработает, что бы вы ни делали.
Это немного странно, но если вы используете функцию внутри функции, то, конечно, действуют некоторые закрывающие устройства. у вас может возникнуть аналогичная проблема в javascript. Я бы посоветовал вообще их не использовать, но если по какой-то причине вы не хотите, то я бы попробовал вот так (не проверено):
class A {
function foo() {
$that = $this;
function bar ($arg){
echo $that->baz, $arg;
}
bar("world !");
}
protected $baz = "Hello ";
}
$qux = new A;
$qux->foo();
ОБНОВИТЬ если вложенная функция действует как глобальная функция, то вы можете передать свой объект в качестве параметра, если вам нужно его использовать:
Функция фу() {
function bar ($o,$arg){
echo $o->baz, $arg;
}
bar($this,"world !");
}
Если я понимаю, чего вы пытаетесь достичь, это может быть так:
<?php
class Foo {
public $prop;
public function __construct($prop) {
$this->prop = $prop;
}
public function __call($name, $arguments) {
if (!isset($this->$name)) {
throw new InvalidArgumentException("No such property: $name");
}
if (! $this->{$name} instanceof Closure) {
throw new InvalidArgumentException("{$name} is not a closure");
}
$c = $this->{$name}->bindTo($this);
return $c(...$arguments);
}
}
$f = new Foo("bar");
$f->bar = function ($arg) {
print_r([$arg, $this->prop]);
};
$f->bar("A");
?>
Таким образом, вы можете по существу исправить любую функцию в классе и вызвать ее так, как если бы она была локальной, даже включая использование $this
. Однако есть два ограничения:
- это кажется бессмысленным, так как черты доступны, за исключением случаев, когда вы добавляете действительно динамически определенные в немодифицируемый пакет
- хотя закрытие может получить доступ к свойствам на
$this
, оно все еще является внешним по отношению к объект, поэтому может получить доступ только к общедоступным свойствам. Попытка получить доступprotected
/private
свойства выйдут из строя.