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

发布于 2024-08-09 19:06:17 字数 440 浏览 4 评论 0原文

我有一个类 Logger,其中有一个方法 Log
由于 LogLogger 实例最常见的用途,因此我已连接 __invoke 来调用 Log

另一个类, “Site”包含一个成员“Log”,它是 Logger 的一个实例。

为什么这会起作用:

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

但不是这样:

$this->Log("Message");

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

I have a class Logger which, among other things has a method Log.
As Log is the most common use of the Logger instance, I have wired __invoke to call Log

Another class, "Site" contains a member "Log", an instance of Logger.

Why would this work:

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

But not this:

$this->Log("Message");

The former fails with "PHP Fatal error: Call to undefined method Site::Log()"
Is this a limitation of the callable object implementation, or am I misunderstanding something?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

む无字情书 2024-08-16 19:06:17

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

但遗憾的是,事实并非如此。

Unfortunately, this is (still) a limitation of PHP, but it makes sense when you think about it, as a class can contain properties and methods that share names. For example:

<?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
?>

If PHP were to allow the syntax you desire, which function would be invoked? Unfortunately, that only leaves us with call_user_func[_array]() (or copying $this->log to another variable and invoking that).

However, it would be nice if the following syntax was acceptable:

<?php
{$test->log}();
?>

But alas, it is not.

拔了角的鹿 2024-08-16 19:06:17

同样的原因,你不能这样做:

$value = $this->getArray()["key"];

甚至这个

$value = getArray()["key"] ;

因为 PHP 语法不能很好地进行速记。

Same reasons you can't do this:

$value = $this->getArray()["key"];

or even this

$value = getArray()["key"];

Because PHP syntax doesn't do short hand very well.

树深时见影 2024-08-16 19:06:17

这可能有效:

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

但也许使用完整调用更容易、更好?似乎没有一种方法可以在一条线上获得您想要的工作。

您问题中的错误表明它正在寻找在不存在的类上定义的函数。可调用对象不是函数,在这种情况下似乎不能将其视为函数。

This may work:

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

But perhaps it's just easier and better to use the full call? There doesn't seem to be a way to get what you want to work on the one line.

The error in your question indicates it is looking for a function defined on the class which doesn't exist. An invokable object isn't a function, and it seems it can't be treated as one in this case.

过潦 2024-08-16 19:06:17

从 php7.4 开始,以下代码对我有用

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

as of php7.4 the following code works for me

($this->Log)("Message");
猫性小仙女 2024-08-16 19:06:17

感谢您的问题和所有的答案!我将分享我的经验,以防它对这个主题上的人有用。

我喜欢以这样的方式定义调试函数,当调试标志打开时,程序会向我描述它正在做什么,并且在编写代码时添加大量日志记录,因为这是我知道的时间最好有哪些情况。然后,当调试标志关闭时,除了布尔检查之外几乎没有任何开销成本,因为仅在调试打开时才调用该函数(并评估参数)。

我以不同的方式在其他语言中使用它,在 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 Wagner 的推荐,我尝试使用括号,它成功了!我不需要将其添加到布尔检查中,只需在调用中添加它,现在代码如下所示并且可以工作:

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

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

Thank you for your question and for all the answers! I'll share my experience in case it comes useful for someone on this subject.

I love defining a debug function in such a way that the program, when debug flag is on, would describe to me what it's doing, and I add a lot of the logging when I write the code, as this is the time when I know best which cases can be there. Then when debug flag is off, there is almost no overhead cost except for boolean checks, since the function is called (and the parameters are evaluated) only in case debug is on.

I used it in other languages in a different way, and in PHP at first I wrote it like this:

const DEBUG_LOGGING = true;
$logdbg = DEBUG_LOGGING ?
    function(...$args) {
        foreach ($args as $arg) {
            echo var_export($arg, true), PHP_EOL;
        }
    } :
    null;

but then it would be in the global scope:

//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
}

and I didn't want to add global variables, which couldn't be put under a namespace. So after checking what can be in a namespace, I defined it inside a class:

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();

but it gave me the same "uninitialized" warning this thread speaks about, and didn't work!

Thanks to this thread and Norbert Wagner's recommendation, I tried with parentheses and it worked! I didn't need to add it on the boolean check, only on the call, and now the code looks like this and works:

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

Dbg::$log && (Dbg::$log)('inside function', $var2, $ar3);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文