1

Assume we have a parent class and a child class. The parent class checks some parameters and decides that the child class would be better suited to handle the given request - is there a way to recreate the existing (parent)-object as an object of the child class from whithin the parent object?

Example of a parent class:

/**
 * Simple car
 */
class car {
    /**
     * The constructor
     */
    public function __construct() {
        // (...)
    }

    /**
     * Add a sunroof to the car
     */
    protected function addSunRoof() {
        // (...)
    }

    /**
     * Parse a config string and configure the car accordingly
     * @param string $config
     */
    public function configure($config) {
        $options = explode(";", $config);

        // Do something for every option in $config string
        foreach ($options as $o) {
            switch ($o) {
                case "sunroof" : 
                    $this->addSunRoof();
                    break;
                case "4x4" :
                    // 'car' does not have support for '4x4', but the child class 'suv' does
                    // -> This 'car' object should therefore 'evolve' and become a 'suv' object - how?
                case "foo" :
                // (...)
            } // switch

        } // foreach
    } // configure
} // car

Example of the child class:

/**
 * SUV car
 */
class suv extends car {
    /**
     * Add 4x4 drive
     */
    protected function add4x4() {
        // (...)
    } // add4x4
} // suv

Now, the most obvious way to get a suv object would be to create it directly from the beginning:

$car = new suv();
$car->configure($config);

The challenge is that I don't know whether a car or a suv object is required when creating the object; I don't know what options the $config string contains until it gets parsed in the $car->configure() method (The string can come from anywhere, e.g. user input).

A simple workaround would be to move the configure method out of car to analyse the string before creating any object - however, it logically belongs to the car object, so I would really like to keep it there :)

Is there a way to solve this puzzle? If not, what would you suggest as the "cleanest" workaround?

Thanks in advance!

Edit:

As it was pointed out, my question is very similar to this one: Cast the current object ($this) to a descendent class The answers there are saying that it's technically possible, but should not be done. However, a convincing alternative has not been suggested yet (It has been suggested to use factories, but I feel this would only solve a part of the problem).

Community
  • 1
  • 1
  • 8
    A parent shouldn't know about its children, full stop. A parent is stand-alone, a child may *extend* and alter its behavior; the parent should be blissfully unaware of that. The child depends on the parent, if the parent also depends on the child you have a conumdrum. – deceze Feb 18 '13 at 21:22
  • 3
    How about using a CarFactory class with configure method returning the best suited instance? The name "configure" is not best name here. – Voooza Feb 18 '13 at 21:22
  • 1
    http://en.wikipedia.org/wiki/Factory_method_pattern – Achrome Feb 18 '13 at 21:25
  • @Voooza, Ashwin Mukhija: If I understand the factory concept correctly, it would mean that I have to parse the config string twice; once in the factory to decide which object to create and once in the object itself - the ability to "configure itself with a string" is a desired feature of the car-class, public setter methods are not really an option. – user2084732 Feb 19 '13 at 08:23
  • Do you want to reconfigure your car on the fly? You want your car to change from Ferrari to Hammer as soon as you leave the higway and change to mini cooper when you are looking for a parking spot? That would be cool. I want that too. Otherwise you can pick your car from factory already configured. – Voooza Feb 19 '13 at 09:27
  • That's exactly what I want. To keep it figuratively: As a pizza boy, I have to buy a car before the first client calls - but I don't know what car I need because I don't know where my clients live when buying the car. I only get the map (config string) when the client calls - and he might live somewhere in the woods... – user2084732 Feb 19 '13 at 10:41
  • @user2084732 "public setter methods are not really an option" - why not? And even if you do not want to add a public setter, you can create an object using a factory, then in the same factory pass parsed configuration string to the configure method. This way you do not have to parse configuration twice. – Jevgenij Evll Apr 09 '13 at 07:03

1 Answers1

0

As said in comments, the most common way to do what you want would be to have a static method taking the string as parameter and returning the correct instance. This way, you would keep the method inside the car class which is, as you said, is the most logical.

By the way, if it is more about adding features on an existing object. You might consider the Decorator pattern. This way, you could have a static method taking the configuration string and the existing car and returning given car decorated with the features matching the configuration. This allows you to be more flexible with all the pros and cons (you could have a sun roof on a Tractor).

Marshall777
  • 1,196
  • 5
  • 15