升级到PHP 7后,日志几乎因这种错误而窒息:
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中将这些错误和这些错误静音?
在PHP 7之前,它们是可以轻松处理E_STRICT的警告类型.现在他们只是陈旧的警告.由于我确实想知道其他警告,我不能完全关闭所有警告.
我没有心智能力来重写这些遗留API,甚至没有提及使用它们的所有软件.猜猜看,没人会为此付出代价.我不是首先开发它们所以我不是那个应该责备的人.(单元测试?十年前不是时尚.)
我想,以避免任何欺骗与func_get_args和类似尽可能.
我真的不想降级到PHP 5.
我仍然想知道其他错误和警告.
有一个干净,很好的方法来实现这一目标吗?
san*_*mai 102
因为并不总是能够纠正你没有写的所有代码,特别是遗留代码......
if (PHP_MAJOR_VERSION >= 7) {
set_error_handler(function ($errno, $errstr) {
return strpos($errstr, 'Declaration of') === 0;
}, E_WARNING);
}
Run Code Online (Sandbox Code Playgroud)
此错误处理程序返回true警告,从警告开始,Declaration of它基本上告诉PHP警告已被处理.这就是PHP不会在其他地方报告此警告的原因.
此外,此代码仅在PHP 7或更高版本中运行.
如果您希望仅在特定代码库方面发生这种情况,那么您可以检查具有错误的文件是属于该代码库还是感兴趣的库:
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);
}
Run Code Online (Sandbox Code Playgroud)
至于实际修复其他人的遗留代码,有很多情况可以在简单和易于管理之间完成.在下面的例子中,class B是它的子类A.请注意,您不一定会通过以下示例删除任何LSP违规.
有些情况很简单.如果在子类中缺少默认参数,只需添加它并继续.例如,在这种情况下:
Declaration of B::foo() should be compatible with A::foo($bar = null)
Run Code Online (Sandbox Code Playgroud)
你会这样做:
- public function foo()
+ public function foo($bar = null)
Run Code Online (Sandbox Code Playgroud)如果在子类中添加了其他约束,请在定义中移除它们,同时在函数体内移动.
Declaration of B::add(Baz $baz) should be compatible with A::add($n)
Run Code Online (Sandbox Code Playgroud)
您可能希望使用断言或根据严重性抛出异常.
- public function add(Baz $baz)
+ public function add($baz)
{
+ assert($baz instanceof Baz);
Run Code Online (Sandbox Code Playgroud)
如果您发现约束仅用于文档目的,请将它们移动到它们所属的位置.
- protected function setValue(Baz $baz)
+ /**
+ * @param Baz $baz
+ */
+ protected function setValue($baz)
{
+ /** @var $baz Baz */
Run Code Online (Sandbox Code Playgroud)如果子类的参数少于超类,并且您可以在超类中使它们成为可选项,只需在子类中添加占位符即可.给定错误字符串:
Declaration of B::foo($param = '') should be compatible with A::foo($x = 40, $y = '')
Run Code Online (Sandbox Code Playgroud)
你会这样做:
- public function foo($param = '')
+ public function foo($param = '', $_ = null)
Run Code Online (Sandbox Code Playgroud)如果你看到子类中需要一些参数,那就把这个问题拿在手里.
- protected function foo($bar)
+ protected function foo($bar = null)
{
+ if (empty($bar['key'])) {
+ throw new Exception("Invalid argument");
+ }
Run Code Online (Sandbox Code Playgroud)有时可能更容易改变超类方法以完全排除可选参数,从而回归func_get_args魔术.不要忘记记录缺失的参数.
/**
+ * @param callable $bar
*/
- public function getFoo($bar = false)
+ public function getFoo()
{
+ if (func_num_args() && $bar = func_get_arg(0)) {
+ // go on with $bar
Run Code Online (Sandbox Code Playgroud)
如果你必须删除多个参数,这肯定会变得非常繁琐.
如果您严重违反替代原则,事情会变得更加有趣.如果你没有输入参数,那么很容易.只需使所有额外参数可选,然后检查它们的存在.给定错误:
Declaration of B::save($key, $value) should be compatible with A::save($foo = NULL)
Run Code Online (Sandbox Code Playgroud)
你会这样做:
- public function save($key, $value)
+ public function save($key = null, $value = null)
{
+ if (func_num_args() < 2) {
+ throw new Exception("Required argument missing");
+ }
Run Code Online (Sandbox Code Playgroud)
请注意,我们无法func_get_args()在此处使用,因为它不考虑默认(未传递)参数.我们只剩下了func_num_args().
如果您有一个具有不同界面的类的整个层次结构,则可能更容易将其进一步分散.在每个类中重命名具有冲突定义的函数.然后在这些类的单个中间父级中添加代理函数:
function save($arg = null) // conforms to the parent
{
$args = func_get_args();
return $this->saveExtra(...$args); // diverged interface
}
Run Code Online (Sandbox Code Playgroud)
这样LSP仍然会被违反,虽然没有警告,但你可以保留你在子类中的所有类型检查.
And*_*rea 21
如果必须使错误无效,则可以在默认的,立即调用的函数表达式中声明该类:
<?php
// unsilenced
class Fooable {
public function foo($a, $b, $c) {}
}
// silenced
@(function () {
class ExtendedFooable extends Fooable {
public function foo($d) {}
}
})();
Run Code Online (Sandbox Code Playgroud)
不过,我强烈建议不要这样做.最好修复你的代码,而不是沉默有关它如何被破坏的警告.
如果您需要保持PHP 5兼容性,请注意上述代码仅适用于PHP 7,因为PHP 5没有统一的表达式语法.要使它与PHP 5一起使用,您需要在调用它之前将该函数分配给变量(或使其成为命名函数):
$_ = function () {
class ExtendedFooable extends Fooable {
public function foo($d) {}
}
};
@$_();
unset($_);
Run Code Online (Sandbox Code Playgroud)
Mat*_*wne 21
对于那些想要实际纠正你的代码而不再触发警告的人:我发现只要你给它们提供默认值,就可以知道你可以在子类中为重写方法添加额外的参数.例如,虽然这会触发警告:
//"Warning: Declaration of B::foo($arg1) should be compatible with A::foo()"
class B extends A {
function foo($arg1) {}
}
class A {
function foo() {}
}
Run Code Online (Sandbox Code Playgroud)
这不会:
class B extends A {
function foo($arg1 = null) {}
}
class A {
function foo() {}
}
Run Code Online (Sandbox Code Playgroud)
Sim*_*mba 17
PHP 7删除了E_STRICT错误级别.有关这方面的信息可以在PHP7兼容性说明中找到.您可能还想阅读在开发PHP 7时讨论过的提案文档.
一个简单的事实就是:这些E_STRICT通知在很多版本之前被引入,试图通知开发人员他们使用了不良做法,但最初并没有试图强制进行任何更改.然而,最近的版本,特别是PHP 7,对这些事情变得更加严格.
您遇到的错误是一个经典案例:
您已在类中定义了一个方法,该方法会覆盖父类中具有相同名称的方法,但您的override方法具有不同的参数签名.
大多数现代编程语言实际上根本不允许这样做.PHP曾经允许开发人员摆脱这样的东西,但是对于每个版本,语言变得越来越严格,特别是现在使用PHP 7 - 他们专门使用了一个新的主要版本号,以便他们可以证明做出重大改变可以打破向后兼容性.
您遇到的问题是因为您已经忽略了警告消息.您的问题意味着这是您要继续使用的解决方案,但"严格"和"弃用"之类的消息应被视为明确警告您的代码可能在将来的版本中中断.通过忽略它们过去几年,你已经有效地置身于现在的状况.(我知道这不是你想听到的,现在并没有真正帮助你的情况,但重要的是要说清楚)
真的没有你正在寻找的那种工作.PHP语言正在发展,如果你想坚持使用PHP 7,你的代码也需要不断发展.如果你真的无法修复代码,那么你要么必须禁止所有警告,要么生活中这些警告会使你的日志变得混乱.
如果你打算坚持使用PHP 7,你需要知道的另一件事是这个版本还有许多其他的兼容性中断,包括一些非常微妙的.如果你的代码处于一个错误状态,就像你报告的那样,这意味着它可能已经存在了很长一段时间,并且可能还有其他问题会导致你在PHP 7中遇到问题.对于像这样的代码,我建议在提交到PHP 7之前对代码进行更彻底的审计.如果你不准备这样做,或者没有准备好修复发现的错误(你的问题的含义是你不是)那么我建议PHP 7可能对你来说太过升级了.
您可以选择恢复到PHP 5.6.我知道你说你不想这样做,但作为一个短期到中期的解决方案,它会让你的事情变得更轻松.坦率地说,我认为这可能是你最好的选择.
小智 9
我同意:第一篇文章中的例子是不好的做法.现在如果你有这个例子怎么办:
class AnimalData {
public $shout;
}
class BirdData extends AnimalData {
public $wingNumber;
}
class DogData extends AnimalData {
public $legNumber;
}
class AnimalManager {
public static function displayProperties(AnimalData $animal) {
var_dump($animal->shout);
}
}
class BirdManager extends AnimalManager {
public static function displayProperties(BirdData $bird) {
self::displayProperties($bird);
var_dump($bird->wingNumber);
}
}
class DogManager extends AnimalManager {
public static function displayProperties(DogData $dog) {
self::displayProperties($dog);
var_dump($dog->legNumber);
}
}
Run Code Online (Sandbox Code Playgroud)
我相信这是一个合法的代码结构,但是这会在我的日志中引发警告,因为"displayProperties"没有相同的参数.此外,我不能通过在它们之后添加"= null"来使它们成为可选项......
在这个具体的例子中,我是否正确地认为这个警告是错误的?
小智 6
我也有这个问题.我有一个类覆盖父类的函数,但覆盖有不同数量的参数.我可以想到一些简单的工作 - 但确实需要进行少量的代码更改.
更改父函数的参数,但使额外的参数可选(例如,函数func($ var1,$ var2 = null) - 这可能是最简单的并且需要更少的代码更改.但是可能不值得在父母,如果它使用了很多其他的地方.所以我和#1一起去了.
如果可能的话,不要在子类函数中传递额外的参数,而是使用global来获取额外的参数.这不是理想的编码; 但无论如何都有可能的创可贴.
| 归档时间: |
|
| 查看次数: |
33714 次 |
| 最近记录: |