静音“声明...应该兼容". PHP 7中的警告 [英] Silence "Declaration ... should be compatible" warnings in PHP 7

查看:159
本文介绍了静音“声明...应该兼容". PHP 7中的警告的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

升级到PHP 7后,日志几乎因此类错误而阻塞:

After upgrade to PHP 7 the logs almost choked on this kind of errors:

PHP Warning: Declaration of Example::do($a, $b, $c) should be compatible with ParentOfExample::do($c = null) in Example.php on line 22548

在PHP 7中,如何使这些错误以及仅这些错误静音?

How do I silence these and only these errors in PHP 7?

  • 在PHP 7之前,它们是E_STRICT类型的警告轻松应对.现在,它们只是普通的旧警告.由于我要做想了解其他警告,因此我不能完全关闭所有警告.

  • Before PHP 7 they were E_STRICT type of warnings which could be easily dealt with. Now they're just plain old warnings. Since I do want to know about other warnings, I can't just turn off all warnings altogether.

我没有能力重写这些旧版API,甚至没有提及使用它们的所有软件.猜猜是什么,也没有人会为此付出代价.我都不是一开始就开发它们的,所以我不是要怪的人. (单元测试?十年前还没有流行.)

I don't have a mental capacity to rewrite these legacy APIs not even mentioning all the software that uses them. Guess what, nobody's going to pay for that too. Neither I develop them in the first place so I'm not the one for blame. (Unit tests? Not in the fashion ten years ago.)

我想避免使用func_get_args且尽可能相似的任何骗术.

I would like to avoid any trickery with func_get_args and similar as much as possible.

我不是真的想降级到PHP 5.

Not really I want to downgrade to PHP 5.

我仍然想了解其他错误和警告.

I still want to know about other errors and warnings.

是否有一种干净而不错的方法来完成此任务?

Is there a clean and nice way to accomplish this?

推荐答案

1.解决方法

由于并非总是能够纠正您没有编写的所有代码,尤其是遗留的代码...

1. Workaround

Since it is not always possible to correct all the code you did not write, especially the legacy one...

if (PHP_MAJOR_VERSION >= 7) {
    set_error_handler(function ($errno, $errstr) {
       return strpos($errstr, 'Declaration of') === 0;
    }, E_WARNING);
}

此错误处理程序以Declaration of开头的警告返回true,该警告基本上告诉PHP已经处理了警告.这就是为什么PHP不会在其他地方报告此警告的原因.

This error handler returns true for warnings beginning with Declaration of which basically tells PHP that a warning was taken care of. That's why PHP won't report this warning elsewhere.

此外,此代码仅在PHP 7或更高版本中运行.

Plus, this code will only run in PHP 7 or higher.

如果您只希望针对特定的代码库执行此操作,则可以检查是否有错误的文件属于该代码库或感兴趣的库:

If you want this to happen only in regard to a specific codebase, then you could check if a file with an error belongs to that codebase or a library of interest:

if (PHP_MAJOR_VERSION >= 7) {
    set_error_handler(function ($errno, $errstr, $file) {
        return strpos($file, 'path/to/legacy/library') !== false &&
            strpos($errstr, 'Declaration of') === 0;
    }, E_WARNING);
}


2.正确的解决方案

对于实际修复别人的旧代码,在许多情况下,这可以在容易和可管理之间完成.在下面的示例中,类BA的子类.请注意,您不一定要通过遵循以下示例来删除任何违反LSP的行为.


2. Proper solution

As for actually fixing someone else's legacy code, there is a number of cases where this could be done between easy and manageable. In examples below class B is a subclass of A. Note that you do not necessarily will remove any LSP violations by following these examples.

  1. 有些情况很容易.如果在子类中缺少默认参数,则只需添加它并继续.例如.在这种情况下:

  1. Some cases are pretty easy. If in a subclass there's a missing default argument, just add it and move on. E.g. in this case:

Declaration of B::foo() should be compatible with A::foo($bar = null)

您会这样做:

- public function foo()
+ public function foo($bar = null)

  • 如果您在子类中添加了其他约束,请在定义中删除它们,同时在函数体内移动.

  • If you have additional constrains added in a subclass, remove them from the definition, while moving inside the function's body.

    Declaration of B::add(Baz $baz) should be compatible with A::add($n)
    

    根据严重性,您可能要使用断言或引发异常.

    You may want to use assertions or throw an exception depending on a severity.

    - public function add(Baz $baz)
    + public function add($baz)
      {
    +     assert($baz instanceof Baz);
    

    如果您发现约束仅用于文档目的,请将它们移到它们所属的位置.

    If you see that the constraints are being used purely for documentation purposes, move them where they belong.

    - protected function setValue(Baz $baz)
    + /**
    +  * @param Baz $baz
    +  */
    + protected function setValue($baz)
      {
    +     /** @var $baz Baz */
    

  • 如果子类的参数比父类少,并且可以使它们在父类中成为可选参数,则只需在子类中添加占位符即可.给定错误字符串:

  • If you subclass has less arguments than a superclass, and you could make them optional in the superclass, just add placeholders in the subclass. Given error string:

    Declaration of B::foo($param = '') should be compatible with A::foo($x = 40, $y = '')
    

    您会这样做:

    - public function foo($param = '')
    + public function foo($param = '', $_ = null)
    

  • 如果您在子类中看到一些必需的参数,则将其交给您.

  • If you see some arguments made required in a subclass, take the matter in your hands.

    - protected function foo($bar)
    + protected function foo($bar = null)
      {
    +     if (empty($bar['key'])) {
    +         throw new Exception("Invalid argument");
    +     }
    

  • 有时,更改超类方法以完全排除可选参数可能会更容易,这又回到了func_get_args魔术上.不要忘记记录缺少的参数.

  • Sometimes it may be easier to alter the superclass method to exclude an optional argument altogether, falling back to func_get_args magic. Do not forget to document the missing argument.

      /**
    +  * @param callable $bar
       */
    - public function getFoo($bar = false)
    + public function getFoo()
      {
    +     if (func_num_args() && $bar = func_get_arg(0)) {
    +         // go on with $bar
    

    如果您必须删除多个参数,那么这可能会变得非常乏味.

    Sure this can become very tedious if you have to remove more than one argument.

    如果您严重违反替代原则,事情会变得更加有趣.如果没有类型化的参数,那么这很容易.只需将所有其他参数设置为可选,然后检查其是否存在.给定错误:

    Things get much more interesting if you have serious violations of substitution principle. If you do not have typed arguments, then it is easy. Just make all extra arguments optional, then check for their presence. Given error:

    Declaration of B::save($key, $value) should be compatible with A::save($foo = NULL)
    

    您会这样做:

    - public function save($key, $value)
    + public function save($key = null, $value = null)
      {
    +     if (func_num_args() < 2) {
    +         throw new Exception("Required argument missing");
    +     }
    

    请注意,此处不能使用func_get_args(),因为它不考虑默认(未传递)参数.我们只剩下func_num_args().

    Note that we couldn't use func_get_args() here because it does not account for default (non-passed) arguments. We are left with only func_num_args().

    如果您的类的整体层次结构具有不同的接口,则将其更进一步地分离可能会更容易.在每个类中重命名具有冲突定义的函数.然后在这些类的单个中介父级中添加代理功能:

    If you have a whole hierarchies of classes with a diverging interface, it may be easier diverge it even further. Rename a function with conflicting definition in every class. Then add a proxy function in a single intermediary parent for these classes:

    function save($arg = null) // conforms to the parent
    {
        $args = func_get_args();
        return $this->saveExtra(...$args); // diverged interface
    }
    

    这样,尽管没有警告,仍然会违反LSP,但是您可以保留子类中的所有类型检查.

    This way LSP would still be violated, although without a warning, but you get to keep all type checks you have in subclasses.

    这篇关于静音“声明...应该兼容". PHP 7中的警告的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆