PHP可调用对象作为对象成员

q1qsirdb  于 2023-06-04  发布在  PHP
关注(0)|答案(5)|浏览(368)

我有一个类Logger,其中有一个方法Log
由于LogLogger示例的最常见用法,因此我将__invoke连接起来调用Log
另一个类“Site”包含成员“Log”,它是Logger的示例。
为什么会这样:

$Log = $this->Log;  
$Log("Message");

但不是这个:

$this->Log("Message");

前一个失败,并显示“PHP Fatal error:调用未定义的方法Site::Log()”
这是可调用对象实现的一个限制,还是我误解了什么?

w8biq8rn

w8biq8rn1#

不幸的是,这(仍然)是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}();
?>

但可惜的是,它不是。

mfuanj7w

mfuanj7w2#

和你不能这么做的原因一样
$value = $this->getArray()["key"];
甚至这个
$value = getArray()["key"];
因为PHP语法不能很好地进行速记。

7cwmlq89

7cwmlq893#

这可能会起作用:

${this->Log}("Message");

但也许使用完整的调用更容易,更好?似乎没有一种方法可以在一条线上得到你想要的工作。
你的问题中的错误表明它正在寻找一个在不存在的类上定义的函数。一个可调用的对象不是一个函数,在这种情况下,它似乎不能被视为一个函数。

zzlelutf

zzlelutf4#

下面的代码是为我工作的

($this->Log)("Message");
8yoxcaq7

8yoxcaq75#

谢谢你的问题和所有的答案!我将分享我的经验,以防它对这个问题上的人有用。
我喜欢这样定义一个调试函数,当调试标志打开时,程序会向我描述它在做什么,当我写代码时,我会添加很多日志记录,因为这是我最清楚哪些情况可能存在的时候。然后当debug flag为off时,除了布尔检查之外,几乎没有开销成本,因为只有在debug为on的情况下才会调用函数(并评估参数)。
我在其他语言中以不同的方式使用它,在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();

但它给了我同样的“未初始化”警告这个线程说,并没有工作!
感谢这个帖子和Norbert瓦格纳的推荐,我尝试了括号,它工作了!我不需要在布尔检查中添加它,只需要在调用中添加它,现在代码看起来像这样并且可以工作:

//the only difference with the previous snippet
Dbg::$log && (Dbg::$log)('outside function', $var1);

Dbg::$log && (Dbg::$log)('inside function', $var2, $ar3);

相关问题