基于条件的继承?

时间:2010-09-20 07:49:49

标签: php inheritance

我试图继承一组不同的父类,甚至不继承任何类,但是根据某些条件。 例如,这就是我想做的事情

$choice = 2;
switch($choice) {
     case 1: 
         class child extends parent1
         break;
     case 2: 
         class child extends parent2
         break;
     default:
         class child 
         //extend nothing
         break;
    }

我认为你可以弄清楚我在这里想要实现的目标。

父类

class car { }

儿童班

class ferari extends car { }
class ford extends car { }

孙子课

class automaticcar { }
class manualcar { }

现在这个大班需要根据使用post从表单发送的值来插入父类。像这样的东西

$brand = $_POST['brand'];

if(isset($brand) && !empty($brand)) {
  class automaticcar extends $brand 
}
else {
  class automaticcar extends car  //or even nothing
}

//And then I wish to write the remaining portion of the clasŠ

5 个答案:

答案 0 :(得分:5)

使用继承基于类的语言无法实现您尝试获取的继承类型。

你可以获得更接近的解决方案是使用一种装饰模式和一些魔术方法。像这样的东西:

$choice = 2;
switch($choice) {
     case 1: 
         $obj = new child(new parent1());
         break;
     case 2: 
         $obj = new child(new  parent2());
         break;
     default:
         //extend nothing
         $obj = new child();
         break;
    }

与孩子相似:

class child {
    function __construct($composeObj) {
        $this->core = $composeObj;
        // wathever you need to iniyialize
    }
    function __call($name, $params) {
        return call_user_func(array($sthis->core, $name), $parameters);
    }
    // other functions
} // eo child

这个解决方案有一些注意事项但是如果你可以处理它们(该对象不属于合成对象的族,call_user_func不通过引用传递参数)这是一个合适的解决方案。

更好的解决方案是sandeepan建议的工厂方法,但你已经拒绝了它。

答案 1 :(得分:1)

法拉利在其提供的属性或方法方面与福特没有什么不同。他们都是汽车。它们的属性只有不同的。不需要创建一个特殊化的子类。而是尝试这条路线:

class Car
{
    protected $_manufacturer;
    protected $_engine;
    protected $_gear;
    protected $_price;
    protected $_color;

    public function __construct($manufacturer, $engine, $gear, $price, $color)
    {
        // setting properties
    }
}

class CarFactory
{
    public static function createFerrari()
    {
        $engine = new Engine(500); // PS
        $gear = new Gear(6, 'manual');
        return new Car('Ferrari', $engine, $gear, '250000', 'red');
    }

    public static function createFord()
    {
        $engine = new Engine(90); // PS
        $gear = new Gear(5, 'automatic');
        return new Car('Ford', $engine, $gear, '50000', 'black');
    }

    // other car creation methods ...
}

如果您扩展某个类,则表示您正在创建 is-a 关系。子类是一个专门的父类。齿轮和发动机不是汽车 ,而是汽车拥有的东西。每当你能够描述一个类来拥有某个东西时,它就是它自己的类的候选者或仅仅是一个属性。它是否属于自己的类取决于封装的东西是否具有独特的状态和责任。

答案 2 :(得分:0)

您的问题是“基于条件的继承是否良好?”然后是的,在许多情况下看来是必要的。但我认为有条件地启动对象而不是在条件内定义扩展类会更好。

<强>更新
据我所知,你希望根据条件拥有子类的不同属性/功能。我在项目中遇到了类似的需求/问题。它与视图逻辑有关。您可以查看How is my approach to reuse view logic in my project?

如果我理解你的问题,那么你应该事先准备好这些子类,就像在单独的php文件中一样: -

child1 class

class1 child extends parent1

child2 class

class2 child extends parent2

在条件部分执行以下操作: -

$choice = 2;
switch($choice) {
     case 1: 
         include /path/to/child1;
         $obj = new child1();
         break;
     case 2: 
         include /path/to/child2;
         $obj = new child2();
         break;
     default:
         include /path/to/child;
         $obj = new child();
         //extend nothing
         break;
    }

答案 3 :(得分:0)

首先,我真的不认为你理解面向对象的原则就足以要求这个功能了。使用PHP实现的OOP风格并不是真的需要它。

您正在请求条件混合等内容。它可以实现它,但它是一个巨大的kludge,应该避免。这是我刚刚在测试一些概念时放在一起的东西:

<?php
    class Mixin
    {
        private $objects = array();
        private $funcs = array();

        public function addMixin(Mixable $object)
        {
            $exported_vars = $object->exportVars();
            foreach ($exported_vars as $key => &$ref)
                $this->$key = &$ref;

            $vars = array();
            foreach (array_keys(get_object_vars($this)) as $key)
                $vars[$key] = &$this->$key;
            $object->importVars($vars);

            $this->objects[] = $object;
        }

        public function __call($method, $args)
        {
            if (!isset($this->funcs[$method]))
            {
                $found = false;
                foreach ($this->objects as $obj)
                {
                    if (method_exists($obj, $method))
                    {
                        $found = true;
                        $this->funcs[$method] = array($obj, $method);
                        break;
                    }
                }

                if (!$found)
                    throw new Exception("method doesn't exist");
            }

            return call_user_func_array($this->funcs[$method], $args);
        }
    }

    class Mixable
    {
        public function exportVars()
        {
            $vars = array();

            foreach (array_keys(get_object_vars($this)) as $key)
            {
                $vars[$key] = &$this->$key;
            }

            return $vars;
        }

        public function importVars($vars)
        {
            foreach ($vars as $key => &$ref)
            {
                $this->$key = &$ref;
            }
        }
    }
?>

您可以使用它:

<?php    
    class Parent1 extends Mixable
    {
        protected $name = 'Parent 1';

        public function p1()
        {
            print "P1\n";
        }
    }

    class Parent2 extends Mixable
    {
        protected $name = 'Parent 2';

        public function p2()
        {
            print "P2\n";
        }
    }

    class Child1 extends Mixin
    {
        public function whoAmI()
        {
            print $this->name."\n";
        }
    }

    $foo = new Child1();
    if (mt_rand(1, 2) == 1)
    {
        $foo->addMixin(new Parent1());
        $foo->p1();
    }
    else
    {
        $foo->addMixin(new Parent2());
        $foo->p2();
    }

    $foo->whoAmI();
?>

请不要尝试使用该代码!即使它已经准备就绪,这也是一个糟糕的概念。我把它放在这里向你展示 的工作原理。

我认为你真正应该做的就是更像工厂模式:构建一个CarFactory类,返回一个正确的子类Car。 (或者您可以在Car类中创建工厂方法。)

可能类似于Car::get($_POST['brand'])

答案 4 :(得分:0)

我知道我差不多六年了。但是为了以防有人再次降落在这里,我决定把它放在这里。

请注意,我并不假设隐含的理解是类名CarFerrariFord等是车辆。以便能够以通用的方式应用这种模式。

我将按优先顺序递减使用以下任一方法:

  • 类别名 PHP Manual (PHP 5 >= 5.3.0, PHP 7)

    // Assuming $my_brand is the required brand 
    if (!class_exists($my_brand))
    {
        // Raise suitable warning here and exit
        exit('Brand ' . $my_brand . 'not found.');
    }
    
    class_alias($my_brand, 'MyBrand');
    
    class AutomaticCar extends MyBrand
    {
    }
    
  • 继承的条件堆叠(工作量太大,但在较大规模的项目中很有用)

    // File: lib/MyBrand/Ferrari.php
    class MyBrand extends Ferrari
    {
    }
    
    // File: lib/MyBrand/Ford.php
    class MyBrand extends Ford
    {
    }
    
    // Then in your main code, assuming $my_brand is the required brand 
    if (!file_exists('lib/MyBrand/' . $my_brand . '.php'))
    {
        // Raise suitable warning here and exit
        exit('Brand ' . $my_brand . 'not found.');
    }
    
    class AutomaticCar extends MyBrand
    {
    }
    

我现在可以使用的其他模式(例如工厂设计和装饰模式)会考虑采用不符合确切主题的不同路线。所以这就是现在。