php严格错误包括

时间:2015-06-04 12:54:28

标签: php strict

如果类在这样的文件中,则看起来不会发生严格错误:

abstract class Food{}

class Meat extends Food{}                    

abstract class Animal{          
    function feed(Food $food){ }
}

class Cat extends Animal{           
    function feed(Meat $meat){
        parent::feed($meat);
    }   
}    

但是如果你把类定义放在单独的文件中并包含它们:

abstract class Food{}

class Meat extends Food{}                    

require 'Animal.php';
require 'Cat.php';

抛出严格的标准错误消息:

  

严格标准:Cat::feed()声明应与c:\ path \ to \ Cat.php中的Animal::feed(Food $food)兼容...

如果所有文件都在一个文件中,即使这样也可以:

class Dog extends Animal{           
  function feed($qty = 1){ 
    for($i = 0; $i < $qty; $i++){
        $Meat = new Meat();
        parent::feed($Meat);
    }       
  } 
}

这是预期的行为吗?

因为MeatFood,所以首先不应该抱怨,对吧? 所以解决方案很简单明了:将所有内容放在一个文件中,并且满足严格的标准;)

任何提示赞赏

2 个答案:

答案 0 :(得分:3)

  

这是预期的行为吗?

不幸的是,是的。与类声明相关的复杂性使得当它们全部出现在同一个脚本中时,并不总是应用严格的规则;每个文件的单个类不会出现此问题。

  

因为肉是一种食物,所以不应该首先抱怨,对吧?

错误有两个原因:

  1. 肉类比食物更小,因此只允许你的后代班级中较小的类型违反LSP;您无法将Cat替换为Animal

  2. 在PHP中,重载方法时参数类型为invariant,即接受的类型必须与父类型完全匹配。虽然可以认为逆变类型是有意义的,但由于技术原因,这是不可能完成的。

  3.   

    因此解决方案简单明了:将所有内容放在一个文件中并满足严格的标准;)

    不,你绝对不应该依赖这种行为。

答案 1 :(得分:1)

PHP在类和名称空间方面的许多奇怪行为之一。

标准解决方案是创建Interface(让我们将其命名为FoodInterface') and implement it in the base class. Then use FoodInterface as the type of the argument of method feed()`:

interface FoodInterface {}

abstract class Food implements FoodInterface {}

class Meat extends Food {}

abstract class Animal {
    function feed(FoodInterface $food) {}
}

class Cat extends Animal {           
    function feed(FoodInterface $meat) {
        parent::feed($meat);
    }
}

FoodInterface界面可以为空,或者您可以在其中声明需要在Animal::feed()中调用的功能。

通过这种方式,您feed() Cat(或任何其他Animal)可以使用任何实现FoodInterface的对象,无论它们是否扩展Food或不是。只要他们实现了界面,就可以将它们提供给任何Animal

class Toy implements FoodInterface {}

$cat = new Cat();
$cat->feed(new Toy());    // He can't eat it but at least he will have some fun :-)

因为您的基类是抽象的,所以它可以充当前面提到的接口。忘记界面,只需使用与Cat::feed()相同的参数类型声明Animal::feed()

然后,在Cat::feed()的实现中,您可以使用instanceof来检查所接收参数的类型是否是您想要的类型(Meat):

abstract class Food {}

class Meat extends Food {}

abstract class Animal {
    function feed(Food $food) {}
}

class Cat extends Animal {           
    function feed(Food $meat) {
        if (! $meat instanceof Meat) {
            throw new InvalidArgumentException("Cats don't eat any Food. Meat is required");
        }

        // Here you are sure the type of $meat is Meat
        // and you can safely invoke any method of class Meat
        parent::feed($meat);
    }
}

评论

第一种方法是正确的方法。第二种方法有其自身的优点,我建议仅在第一种方法由于某种原因不可能时才使用它。