1.解决方法
由于并非总能纠正所有您未编写的代码,尤其是遗留的代码...
if (PHP_MAJOR_VERSION >= 7) {
set_error_handler(function ($errno, $errstr) {
return strpos($errstr, 'Declaration of') === 0;
}, E_WARNING);
}
该错误处理程序返回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);
}
2.正确的解决方案
至于实际修复别人的遗留代码,在许多情况下可以在容易和可管理之间完成。在下面的示例中,classB
是的子类A
。请注意,您不一定会通过遵循以下示例来删除任何违反LSP的行为。
有些情况很容易。如果在子类中缺少默认参数,则只需添加它并继续。例如,在这种情况下:
Declaration of B::foo() should be compatible with A::foo($bar = null)
您可以这样做:
- public function foo()
+ public function foo($bar = null)
如果您在子类中添加了其他约束,则在函数内部移动时将其从定义中删除。
Declaration of B::add(Baz $baz) should be compatible with A::add($n)
您可能要使用断言或引发异常,具体取决于严重性。
- public function add(Baz $baz)
+ public function add($baz)
{
+ assert($baz instanceof Baz);
如果看到约束仅用于文档目的,请将它们移到它们所属的位置。
- protected function setValue(Baz $baz)
+ /**
+ * @param Baz $baz
+ */
+ protected function setValue($baz)
{
+
如果子类的参数少于父类,并且可以使它们在父类中成为可选参数,则只需在子类中添加占位符即可。给定错误字符串:
Declaration of B::foo($param = '') should be compatible with A::foo($x = 40, $y = '')
您可以这样做:
- public function foo($param = '')
+ public function foo($param = '', $_ = null)
如果您在子类中看到某些必需的参数,请直接处理。
- protected function foo($bar)
+ protected function foo($bar = null)
{
+ if (empty($bar['key'])) {
+ throw new Exception("Invalid argument");
+ }
有时,更改超类方法以完全排除可选参数可能更容易,这又回到了func_get_args
魔术上。不要忘记记录缺少的参数。
- public function getFoo($bar = false)
+ public function getFoo()
{
+ if (func_num_args() && $bar = func_get_arg(0)) {
+
如果您必须删除多个参数,那么这肯定会变得非常乏味。
如果您严重违反替代原则,事情会变得更加有趣。如果没有类型化的参数,那么这很容易。只需将所有其他参数设为可选,然后检查其是否存在。给定错误:
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()
。
如果您拥有带有不同接口的整个类层次结构,则更容易将其进一步分开。在每个类中重命名具有冲突定义的函数。然后在单个中介父级中为这些类添加代理功能:
function save($arg = null) // conforms to the parent
{
$args = func_get_args();
return $this->saveExtra(...$args);
}
尽管没有警告,但仍然会违反LSP的这种方式,但是您必须保留子类中的所有类型检查。
Warnings
不是Errors
。而且,您不应尝试使它们“静音”,而应解决该问题。警告的目的是告诉您您的代码将来会遇到问题。