Home > Blockchain >  Load Child Content from Parent Based on Child Variable
Load Child Content from Parent Based on Child Variable

Time:01-14

I have simple parent class named fruits and several childs, like this:

Parent:

class fruits
{

    public function __construct()
    {

        $this->render();
        
    }

    protected function render()
    {

    }

}

Child (banana):

class banana extends fruits
{

    public $identity = 'banana';

    protected function render()
    {

        echo 'This text will describe all about banana';

    }

}

Child (orange):

class orange extends fruits
{

    public $identity = 'orange';

    protected function render()
    {

        echo 'This text will describe all about orange';

    }

}

The question is, how to load/display child content from parent based on child variable ($identity) ? I want to use the following code:

$fruits = new fruits( 'banana' );

and will get the child content that generated from render function, for example will get like this:

This text will describe all about banana etc...

Thank you and really appreciate for any help...

--- EDITED ----------------------------

As suggested by @quack, how about this code?

Parent:

<?php

class Fruit
{

    public function __construct( $identity = '' )
    {

        $this->load( $identity );

    }

    private function load( $identity )
    {

        foreach ( $this->getChild() as $child ) {

            $reflectionClass = new ReflectionClass( $child );
            $childData       = $reflectionClass->getDefaultProperties();

            if ( isset( $childData['identity'] ) && ( $childData['identity'] === $identity ) ) {

                $component = new $child();

                if ( method_exists( $component, 'render' ) ) {
                    $component->render();
                }

                break;

            }

        }

    }

    private function getChild()
    {

        $children = array();

        foreach ( get_declared_classes() as $class ) {

            if ( is_subclass_of( $class, 'Fruit' ) ) {
                $children[] = $class;
            }

        }

        return $children;

    }

}

Child

<?php

class Banana extends Fruit
{

    public $identity = 'banana';

    protected function render()
    {

        print "Hi, I'am $this->identity";

    }

}

And will load with this:

new Fruit('banana');

CodePudding user response:

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');

CodePudding user response:

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!
  •  Tags:  
  • Related