【问题标题】:class substitution in phpphp中的类替换
【发布时间】:2013-05-16 14:33:02
【问题描述】:

有什么方法可以让它工作吗?见例子:

class car {
        function __construct($type){
                switch ($type) {
                        case 'big' : return new big_car();
                        case 'small' : return new small_car();
                }
        }
        function whatisit () {
                echo "this is car ;( \n";
        }
}

class big_car extends car {
        function __construct(){}
        function whatisit () {
                echo "this is big car ;) \n";
        }
}

class small_car extends car {
        function __construct(){}
        function whatisit () {
                echo "this is small car ;) \n";
        }
}

所以目标是这样使用它:

$mycar = new car('big');
$mycar->whatisit(); // i want it to say that it's big

我很想这是不好的方式,它不能以这种方式工作,但也许有一个技巧?

PS:: 我知道我可以为此使用特殊的静态方法,但是...

【问题讨论】:

  • 构造函数不能在 PHP 中返回值;你需要另一种方法。
  • @kitty 为你的昵称+头像点赞。
  • 你需要添加一个“汽车”界面和一个“汽车”工厂 - 试图同时做这两个是丑陋和困难的。

标签: php class oop constructor


【解决方案1】:

你需要一个汽车工厂来制造新车;这不是 JavaScript :)

class car_factory 
{
    function create_car($type = null) 
    {
        switch ($type) {
             case 'big':
                 return new big_car();

             case 'small':
                 return new small_car();

             case null:
                 return new car();
        }
        throw new InvalidArgumentException($type);
    }
}

$factory = new car_factory;
$small_car = $factory->create_car('small');
$std_car = $factory->create_car();

当然,您应该从原始代码中删除__construct 函数。

作为 cmets 中的mentioned,您可以通过使用动态类来完全概括这一点,假设类扩展具有相同的构造函数并且类命名是一致的:

class car_factory
{
    function create_car($type = null)
    {
        if (is_null($type)) {
            return new car();
        }

        $class = "{$type}_car";
        if (class_exists($class)) {
            $obj = new $class();

            if ($obj instanceof car) {
                return $obj;
            }
        }

        throw new InvalidArgumentException($type);
    }
}

就我个人而言,无论哪种方式,我都没有偏好;如果可扩展性是一个关键因素,那就去吧,否则坚持简单的switch

【讨论】:

  • 按照他想要的方式行事我相信当参数不是bigsmall时应该return new car();,而不是抛出异常。
  • 这个例子扩展性不是很好。如果添加其他类型,则需要更改类实现。您可以尝试根据参数$type:$class = "{$type}_car"; return new $class() 进行实例化。在这种情况下,您所要做的就是保持命名约定。
  • @HenriqueBarcelos 已添加到答案中。
【解决方案2】:

[...]假设类扩展具有相同的构造函数并且类命名是一致的,您可以通过使用动态类来完全概括这一点

您可以使用反射增加更多的灵活性:

class car_factory
{
    function create_car($class = null, $constructorArgs = array())
    {
        if (is_null($class)) {
            return new car();
        }

        try {
           $refl = new ReflectionClass($class);
           if (!$refl->isSubclassOf('car') {
               throw new DomainException("Type: {$class} is not a car type");
           }
           return $refl->newIntanceArgs($constructorArgs);
        } catch(ReflectionException $e) {
           throw new DomainException("Invalid car type: {$class}");
        }
    }
}

现在使用:

$factory = new car_factory();
$car1 = $factory->create_car('big_car');
$car2 = $factory->create_car('small_car');
$car3 = $factory->create_car('fancy_car_name_with_constructor_args', array("I'm fancy!"));

【讨论】:

  • 另外,如果你只想传递对象,你可以跳过 relfection 并使用 type-hinting: function __construct(\Car $car) { $this->car = $car; }
  • 在这种情况下,您必须实例化一个对象并将其传递给工厂,那么,工厂是做什么用的?
  • 是的,我不是在谈论这个具体案例 - 只是为可能正在阅读此答案的任何人发布。它实际上是 DI 设计,而不是工厂模式,这似乎更适合测试。
  • 为什么说DI设计比工厂方法测试更好?
  • 因为大多数工厂与他们正在创建的对象有更多的连接,这些容器只定义了他们期望的对象类型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-06-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-02
相关资源
最近更新 更多