Вызываемый объект PHP как член объекта
У меня есть класс Logger
который, между прочим, имеет метод Log
,
Как Log
является наиболее распространенным использованием Logger
Например, я подключен __invoke
звонить Log
Другой класс "Сайт" содержит член "Журнал", экземпляр Logger.
Почему это работает:
$Log = $this->Log;
$Log("Message");
Но не это:
$this->Log("Message");
Первый завершается с ошибкой "PHP Fatal error: вызов неопределенного метода Site::Log()"
Это ограничение реализации вызываемого объекта или я что-то неправильно понимаю?
5 ответов
По тем же причинам, по которым вы не можете сделать это:
$value = $this->getArray()["key"];
или даже это
$value = getArray()["key"];
Потому что синтаксис PHP не очень хорошо работает.
К сожалению, это (все еще) ограничение PHP, но имеет смысл, когда вы думаете об этом, поскольку класс может содержать свойства и методы, которые совместно используют имена. Например:
<?php
class Test {
public $log;
public function __construct() {
$this->log = function() {
echo 'In Test::log property';
};
}
public function log() {
echo 'In Test::log() method';
}
}
$test = new Test;
$test->log(); // In Test::log() method
call_user_func($test->log); // In Test::log property
?>
Если бы PHP разрешил синтаксис по вашему желанию, какая функция была бы вызвана? К сожалению, это только оставляет нас с call_user_func[_array]()
(или копирование $this->log
в другую переменную и вызывая это).
Однако было бы неплохо, если бы следующий синтаксис был приемлемым:
<?php
{$test->log}();
?>
Но, увы, это не так.
Это может работать:
${this->Log}("Message");
Но, может быть, проще и лучше использовать полный вызов? Кажется, нет способа получить то, что вы хотите работать в одной строке.
Ошибка в вашем вопросе указывает на то, что он ищет функцию, определенную в классе, которая не существует. Вызываемый объект не является функцией, и кажется, что в этом случае он не может рассматриваться как объект.
с php7.4 для меня работает следующий код
($this->Log)("Message");
Спасибо за ваш вопрос и за все ответы! Поделюсь своим опытом, вдруг кому-нибудь пригодится по этой теме.
Мне нравится определять функцию отладки таким образом, чтобы программа, когда включен флаг отладки, описывала мне, что она делает, и я добавляю много журналов, когда пишу код, так как это время, когда я знаю лучше всего, какие случаи могут быть там. Тогда, когда флаг отладки выключен, накладные расходы практически отсутствуют, за исключением логических проверок, поскольку функция вызывается (и оцениваются параметры) только в случае, если отладка включена.
В других языках я использовал его по-другому, а в PHP сначала написал так:
const DEBUG_LOGGING = true;
$logdbg = DEBUG_LOGGING ?
function(...$args) {
foreach ($args as $arg) {
echo var_export($arg, true), PHP_EOL;
}
} :
null;
но тогда это будет в глобальной области:
//this would work:
$logdbg && $logdbg($var1, $var2);
function test() {
//some code
//this wouldn't work:
$logdbg && $logdbg($var3, $var4);
//it would have to be:
global $logdbg; $logdbg && $logdbg($var3, $var4);
//other code
}
и я не хотел добавлять глобальные переменные, которые нельзя было бы поместить в пространство имен. Итак, проверив, что может быть в пространстве имен, я определил это внутри класса:
const DEBUG_LOGGING = true;
class Dbg {
public static $log = null;
public static function init() {
if (DEBUG_LOGGING) {
self::$log = function(...$args) {
foreach ($args as $arg) {
echo var_export($arg, true), PHP_EOL;
}
};
}
}
}
Dbg::init();
Dbg::$log && Dbg::$log('outside function', $var1);
function test() {
//some code
Dbg::$log && Dbg::$log('inside function', $var2, $ar3);
//other code
}
test();
но он выдал мне то же самое «неинициализированное» предупреждение, о котором говорится в этой теме, и не сработало!
Благодаря этой теме и рекомендации Норберта Вагнера я попробовал использовать круглые скобки, и это сработало! Мне не нужно было добавлять его при логической проверке, только при вызове, и теперь код выглядит так и работает:
//the only difference with the previous snippet
Dbg::$log && (Dbg::$log)('outside function', $var1);
Dbg::$log && (Dbg::$log)('inside function', $var2, $ar3);