【问题标题】:Is it possible to intercept the call to non-existing function?是否可以拦截对不存在函数的调用?
【发布时间】:2016-02-23 20:27:02
【问题描述】:

PHP 有其神奇的方法__call__callStatic,它们允许拦截对不存在的方法 的调用。我正在寻找一种方法来拦截对不存在的 function (位于命名空间内的函数,而不是类型)的调用。

可以做(PHP7)吗?

我曾经考虑过将函数放在代理类中,但是命名空间可以跨越多个文件,如果我没记错的话,PHP 没有部分类,因此这种方法没有用。

更新:每个命名空间有多个文件问题。

假设我有文件 A.php 和 B.php,它们都具有相同的命名空间,例如 Text。考虑将所有功能放到代理类中。现在我有文件 C.php,我打电话给Text\indexOf(...)。但是我不知道这是Text\proxyA::indexOf 还是Text\proxyB::indexOf,因为我拥有的所有信息都是命名空间的名称——Text——和函数名称。所以从调用者的角度来看,我很高兴。

【问题讨论】:

  • 如果“拦截”是指“通过返回我自己选择的值使呼叫正常解决”,那么不,这是不可能的。但我真的很好奇——用例会是什么?
  • @Jon,拦截我的意思是 __callStatic 所做的只有一个区别——目标是命名空间而不是类型。目的,我正在研究类似于 C++ 中的模板的东西,我会拦截一个函数调用,对名称进行分解,然后调用函数工厂,它会生成(然后调用)函数的专用版本(我使用 PHP 作为我的后端语言:aboutskila.wordpress.com)。
  • 好吧,如果你需要这个特性,那你为什么要编译直接函数调用呢?您可以改为编译为 resolve_function_call('mangled_name', ['argument', 'list']) 并解决问题。或者甚至用专门为此目的制作的类型上的静态方法调用替换裸函数调用,这将用__callStatic拦截它们。
  • @Jon,是的,这就是我现在正在考虑的——我正在寻找拦截,因为它已经用于模板类型,所以我更愿意使用相同的机制(更少的代码=更少的错误)。当然,如果不可能,我会为类型和函数实现两种不同的方式。至于静态方法作为我已经写过的伪装函数——不可能,每个命名空间可以有多个文件。您能否将您的最后一条评论作为常规答案发表?谢谢。
  • 另外,我还有一个想法。您可以利用自动加载和代理类的想法来实现 codegen-once-then-always-call-without-overhead。我做了一个PoChere,可能更接近你的想象?

标签: php


【解决方案1】:

使用 PHP7+,您可以捕获对未定义函数的调用:

try {
    not_exist();
} catch (\Error $e) {
    echo 'ERROR: ' . $e->getMessage();
}

然后您可以使用 set_exception_handler 来捕捉它,而不会将它放在 try/catch 块中:

set_exception_handler(function($e) {
    echo '<BR>ERROR: ' . $e->getMessage();
});

not_exist();

请注意,您需要使用set_exception_handler 而不是set_error_handler

【讨论】:

  • 谢谢,但您仍然需要编写 try-catch,更糟糕的是使用伪造的 catch 子句以避免捕获异常。由于异常是昂贵的机制,因此这并没有真正为先前的答案添加任何新内容。
  • 为什么还要写catch?什么是假渔获?
  • “如果在 try/catch 块中未捕获到异常,则设置默认异常处理程序。”。这意味着 try-catch 必须首先存在(否则程序崩溃),所以我必须只有 try-catch 才不会捕获该异常。
  • 老实说,似乎不像你说的那样。
【解决方案2】:

从 PHP7 开始,您可以捕获未定义的函数调用:

try {
    idontexist();
} catch (\Error $e) {
    echo $e->getMessage();
}

没有办法像__call 一样使用它,当然除了通过自定义错误处理程序。

演示:https://3v4l.org/j4WRB

【讨论】:

  • 谢谢,但实际上这并不可行——因为您必须将 every 函数调用包装在 try-catch 中,而且您必须非常注意到异常及其堆栈 - 可能是您调用现有函数的情况,但此函数调用了您忘记包装的不存在的函数。
  • 您没有错,但不幸的是,您只能使用这些。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-25
  • 1970-01-01
相关资源
最近更新 更多