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!