#php #lambda #closures
#php #лямбда — выражение #закрытие #лямбда #замыкания
Вопрос:
Я создал не очень сложный тестовый код (протестирован в PHP 5.5.12):
<?php
class Test
{
private $cached = null;
public function __construct()
{
$this->cached = [];
$this->cached[0] = 12;
}
function wrap($function, $index)
{
if (isset($this->cached[$index])) {
return $this->cached[$index];
}
$result = call_user_func($function);
return $result;
}
}
class B
{
public function run()
{
$x = 6;
$obj = new Test();
$value = $obj->wrap(
function () use ($x) {
return $this->test($x);
},
1
);
echo $value."<br />";
}
protected function test($x)
{
echo "I'm running ";
return $x * $x;
}
}
class C extends B
{
public function run()
{
$x = 6;
$obj = new Test();
$myFunc = function () use ($x) {
return $this->test($x);
};
$value = $obj->wrap($myFunc, 1);
echo $value."<br />";
}
}
class D extends B
{
public function run()
{
$x = 6;
$obj = new Test();
$value = $obj->wrap(array($this, 'test'), 1);
echo $value."<br />";
}
}
$b = new B();
$b->run();
$c = new C();
$c->run();
$d = new D();
$d->run();
Возможно, есть некоторые части кода, о которых вы могли бы сказать, что это можно было бы сделать лучше, но главное — это функция замыкания и вызываемая функция. Эти классы имитируют очень простым способом систему кэширования. Если данные находятся в кэше, они возвращают данные из кэша, в противном случае вызывается функция, которая получает данные (конечно, эта система кэширования не работает, потому что в этом нет необходимости — это просто пример кода).
Вопросы:
1) Почему при использовании object $d
я получаю следующее предупреждение:
call_user_func() expects parameter 1 to be a valid callback, cannot access protected method D::test()
и возможно ли запустить защищенный метод из родительского? Когда я меняю этот метод с защищенного на общедоступный, он может быть запущен без проблем
2) Как вы, наверное, заметили, я хочу использовать некоторые аргументы для функции, которую я вызываю с помощью call_user_sync
. К сожалению, я не знаю этих параметров при вызове call_user_func
, поэтому в классах B и C я использовал замыкания, где я могу использовать / передавать дополнительные параметры. У меня есть 2 дополнительных вопроса, связанных с этим:
-
является ли это способом, при котором замыкания полезны и обычно используются?
-
возможно ли с помощью object
$d
передавать параметры в метод тестирования без использования замыканий, но не при вызовеcall_user_sync
, а внутри классаD
?
Комментарии:
1. возможно ли запустить защищенный метод из родительского? Это не то, что вы делаете. Вы не запускаете защищенный метод из родительского. Вы пытаетесь вызвать защищенный метод
Test
экземпляра внутри методаD
экземпляра.2. Вы уверены? В моем коде я вижу, что пытаюсь вызвать защищенный метод
test
B
класса (который является родительским дляD
класса), и когда я меняю этот метод на общедоступный, этот метод запускается3. Вы можете использовать
array($this, 'method')
с частными / защищенными методами только при использовании в том же контексте. Когда вы создаете объект$obj
внутри функции и передаете обратныйarray($this, 'test')
вызов этой объектной функции, он передается без контекста. ВнутриTest::wrap
функции обратный вызов вызывается как$objectOfClassD->test(1)
, а не$this->test(1)
как, и методD::test()
защищен. Когда выD::test()
публикуете его, он доступен из любого контекста, и предупреждение не генерируется.
Ответ №1:
Важно отметить область действия во время выполнения. Вы создаете обратный вызов в правильной области, но вы выполняете обратный вызов в другом объекте без доступа к protected
методу (обратный вызов get выполняется class Test
не в родительском или дочернем элементе class B
.
Я столкнулся с этой проблемой некоторое время назад, когда писал свой собственный класс диспетчера. Одним из вариантов было установить «родительский» для диспетчера и передать диспетчеру в качестве одного из параметров при обратном вызове. Затем обратный вызов проверяет «родительский», связанный с диспетчером === $this
, а затем знает, что у него есть доступ, и отправляется в город.
Вы должны выполнить свою собственную проверку доступа, вот в чем дело.