Search code examples
phpvariablesclassobjectorganization

PHP: How to loop through a dynamic number of classes


I'm wanting to detect all objects(classes) defined in a php file (example: flavors.php). The number of objects will be defined dynamically, so I need to process the available objects with a function at runtime until the objects are exhausted. After the objects are exhausted the program stops.

I have full control over the code, so if there is a better way to store the variables, and keep them organized using only php, please let me know.

As a learning experience, I'm trying to make php manipulate a set of objects without knowing the number, or the names of the objects that exist in advance.

This is the logic I'm trying to code:

while(THERE ARE STILL CLASSES TO PROCESS IN FLAVORS.php)
{
  $var = description_generator(CLASS_NAME SENT TO THE FUNCTION);
  print($var);
}

For context this is the entire program:

flavors.php

class vanilla
{
    // property declaration
    public $color = 'white';
    public $price = '1.25';
}

class chocolate
{
    // property declaration
    public $color = 'brown';
    public $price = '1.50';
}

main.php
{
function description_generator($class_name)
{

    $selected_flavor_class = new $class_name();
    $flavor_color = $selected_flavor_class->flavor_color;
    $flavor_price = $selected_flavor_class->flavor_price;

    return "$flavor_color"."<br />"."$flavor_price";
}

while(THERE ARE STILL CLASSES TO PROCESS)
{
    print($var = description_generator(CLASS_NAME));
}

To summarize, is there a way to make PHP process through an undetermined number of classes? Also is there a better way to create and organize objects that store multiple variables such as chocolate = 'brown', '1.50' without just using a simple array?


Solution

  • You can use the Zend_Reflection package, which extends the regular Reflection API.

    $r = new Zend_Reflection_File('flavors.php');
    $classes = $r->getClasses();
    echo "File holds " . count($classes) . ":\n";
    foreach ($classes as $class) {
        echo $class->getName() . "\n";
    }
    

    Since Zend Framework has a use-at-will architecture, you do not have to use any of the other classes. You do not have to migrate your application to Zend Framework and can use Zend_Reflection standalone.

    Also, you might want to give your classes an interface:

    interface IFlavor
    {
        public function getName();
        public function getPrice();
        public function getColor();
    }
    

    This way, you can reflect whether a class is a Flavor type, e.g.

    $class->implementsInterface('IFlavor')
    

    to make sure the classes in the file really are Flavors. This will also make your code more maintainable because it will ensure your flavors all have the same basic methods and you can use the interface as TypeHint and it is generally good practise to code against an interface.

    However, if the flavor classes only hold these two properties and have no other responsibility, you might want to make them into a single Flavor class, instead of having multiple different classes e.g.

    class Flavor implements IFlavor
    {
        protected $_name;
        protected $_color;
        protected $_price;
    
        public function __construct($name, $color, $price)
        {
            $this->_name  = $name;
            $this->_color = $color;
            $this->_price = $price;
        }
    
        // getter methods
    }
    

    Instead of using Reflection to find classes in your flavors file, you could simply use a Config file to store available flavors. Have a class that knows how to load the config file and give it a method to lazy init Flavors as needed. Since the Flavors are effectively Value Objects (in the DDD sense), you dont need more than one Flavor instance of the same name, so the managing class could also hold any previously created instances and return those when requested.