Load Child Content from Parent Based on Child Variable

Solution 1:

Maybe you need a static function to create the instance like this:

class fruits
{
    public static function getInstance($bananaOrange)
    {
        if ($bananaOrange == 'banana')
        {
            return new banana();
        }
        elseif ($bananaOrange == 'orange')
        {
            return new orange();
        }
    }


    public function __construct()
    {

        $this->render();

    }

    protected function render()
    {

    }

}

$fruits = fruits::getInstance('banana');

Solution 2:

I was quite interested by your question and not satisfied with the factories using some if, else or switch tests so I finally got this solution, which also handles parameters to give to the constructors of each fruit. Each fruit has some different properties so I used an array but you could also use variable length of constructor parameters. I prefered the array solution because the order isn't important. You could improve it to check the parameter names and rise an error if they don't exist for that fruit.

<?php

class FruitException extends Exception { }

abstract class Fruit {
    protected $fruitName = '';

    static public function create($fruitName, $fruitProperties)
    {
        // The class name may not be written correctly.
        $fruitName = ucwords($fruitName);

        if (!class_exists($fruitName) || get_parent_class($fruitName) !== self::class) {
            throw new FruitException("The fruit type '$fruitName' does not exist!");
        }

        return new $fruitName($fruitProperties);
    }

    abstract protected function display();
}

class Banana extends Fruit {
    public const DEFAULT_LENGTH = 15; // cm
    public const MAX_LENGTH = 30; // cm

    private $length = self::DEFAULT_LENGTH;

    public function __construct($properties)
    {
        $this->fruitName = 'Banana';
        extract($properties); // Create variables from array keys and values.
        if (isset($length)) {
            if (!is_numeric($length) || $length < 0 || $length > self::MAX_LENGTH) {
                throw new FruitException('The given banana length is not valid!');
            }
            $this->length = $length;
        }
    }

    public function display()
    {
        print "I'm a banana and my length is $this->length cm\n";
    }
}

class Orange extends Fruit {
    public const DEFAULT_DIAMETER = 9; // cm
    public const MAX_DIAMETER = 15; // cm

    private $diameter = 9; // 

    public function __construct($properties)
    {
        $this->fruitName = 'Orange';
        extract($properties); // Create variables from array keys and values.
        if (isset($diameter)) {
            if (!is_numeric($diameter) || $diameter < 0 || $diameter > self::MAX_DIAMETER) {
                throw new FruitException('The given orange diameter is not valid!');
            }
            $this->diameter = $diameter;
        }
    }

    public function display()
    {
        print "I'm an orange and my diameter is $this->diameter cm\n";
    }
}

class Car {
    // This is not a kind of fruit!
}

$fruits = [
    'Orange' => ['diameter' => 8], 
    'banana' => ['length' => 17], // missing capital first letter.
    'car' => ['color' => 'blue', 'manufacturer' => 'Ferrari'], // Existing class definition but not a fruit.
    'Apple' => ['color' => 'green', 'diameter' => 7.5], // Inexisting fruit type.
];

foreach ($fruits as $fruitName => $fruitProperties) {
    try {
        $fruitInstance = Fruit::create($fruitName, $fruitProperties);
        $fruitInstance->display();            
    }
    catch (FruitException $e) {
        fprintf(STDERR, "ERROR: %s\n", $e->getMessage());
    }
}

This will output the following:

I'm an orange and my diameter is 8 cm
I'm a banana and my length is 17 cm

and this in the standard error stream:

ERROR: The fruit type 'Car' does not exist!
ERROR: The fruit type 'Apple' does not exist!