views:

105

answers:

4

I am trying to inherit a set of different parent class and even not inherit any class but as per some condition. For example, Here is what I would like to do

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

I think you can figure out what I am trying achieve here.

parent classes

class car { }

Child classes

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

grandchild classes

class automaticcar { }
class manualcar { }

Now this grandclasses need to interit a parent as per the value sent from the form using post. Something like this

$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 class

A: 

Is your question "Condition based inheritance good?" Then yes it looks necessary in many cases. But I think it would be better to initiate objects conditionally instead of defining extended classes inside condition.

Updates
As far as I understand you want to have different attributes/functions of the child class depending on condition. I faced a similar need/problem in my project. There it was relating to view logic. You may check http://stackoverflow.com/questions/3475935/how-is-my-approach-to-reuse-view-logic-in-my-project

If I understand your problem correctly, then you should have the child classes ready beforehand like this in separate php files:-

child1 class

class1 child extends parent1

child2 class

class2 child extends parent2

And in the condition part do something like:-

$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;
    }
sandeepan
no no, I want same child to inherit different parent according to cases.
mrNepal
Are you using a MVC architecture? In what context are you using this class? What code is there inside your child and parent classes?
sandeepan
+3  A: 

The kind of inheritance you are trying to obtain is not attainable using a language which inheritance is based on classes.

The closer solution you can obtain is using a sort of decorator pattern with a bit of magic methods. something like this:

$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;
    }

with child being similar to this:

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

This solution have some caveats but if you can cope with them (the object does not belongs to the family of the composited object, call_user_func does not pass the parameters by reference) this is a suitable solution.

A better solution is the factory approach suggested by sandeepan but you already refused it.

Eineki
+1  A: 

A Ferrari is not different to a Ford in the properties or methods it supplies. They are both still cars. They just have different values for their attributes. Creating a spezialized subclass shouldn't be necessary for that. Instead try this route:

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 ...
}

If you extend a class, you are creating an is-a relationship. The subclass is a specialized parent class. Gear and Engine is nothing a Car is, but something a car has. Whenever you can describe a class to have something, it's a candidate for it's own class or for just being an attribute. Whether it should be it's own class depends on whether the thing encapsulated own unique state and responsibiliy.

Gordon
@Gordon, That was a real life example, trying to express what I need. I just want to be able to inherit different but single parent classes as per conditions.
mrNepal
@MrNepal that doesnt sound feasible. Either a subclass *is-a* specialization of parent class or it's not. A Ferrari doesn't stop being a Car because of some condition. That's illogical. Please try to update your question with more details.
Gordon
@mrNepal: "I just want" - so that's the only reason? ;-) Seriously, there isn't a keyword or language-construct that let's you do what you've explained and the example is better solved differently.
VolkerK
A: 

First off, I really don't think you understand object oriented principles well enough to ask for this functionality. It's not really needed with the style of OOP that PHP implements.

You are requesting something like conditional mix-ins. It's possible to implement it, but it is a huge kludge and should be avoided. Here's something I put together a while ago when I was just testing some concepts:

<?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;
            }
        }
    }
?>

You would use it like:

<?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();
?>

Please do not try to use the code! Even if it were production ready, it's a terrible concept. I put it here to show you how it would work.

I think what you really should be doing is something more like a Factory pattern: build a CarFactory class that returns a properly subclassed Car. (Or you could create a factory method within a Car class.)

It could be something like Car::get($_POST['brand']).

konforce