views:

770

answers:

4

I have several static factory patterns in my PHP library. However, memory footprint is getting out of hand and we want to reduce the number of files required during execution time. Here is an example of where we are today:

require_once('Car.php');
require_once('Truck.php');

abstract class Auto
{
    // ... some stuff ...

    public static function Create($type)
    {
        switch ($type) {
            case 'Truck':
                return new Truck();
                break;
            case 'Car':
            default:
                return new Car();
                break;
        }
    }
}

This is undesirable because Car.php AND Truck.php will need to be included even though only one or the other may be needed. As far as I know, require/include and their ..._once variation include libraries at the same scope as it's call. Is this true?

If so, I believe this would lead to a memory leak:

    abstract class Auto
    {
        // ... some stuff ...

        public static function Create($type)
        {
            switch ($type) {
                case 'Truck':
                    require_once('Truck.php');
                    return new Truck();
                    break;
                case 'Car':
                default:
                    require_once('Car.php');
                    return new Car();
                    break;
            }
        }
    }

It looks to me that in the 2nd example, multiple calls to Create() would lead to multiple requires because of the scope of the call even though the require_once flavor is used.

Is this true? What is the best way to include libraries dynamically in php in an example such as these?

Thanks!

+4  A: 

The Autoload facility is often seen as Evil, but it works at these task quite nicely.

If you can get a good filesystem <-> classname mapping so you can, when given a class to provide, find it, then it will save you overhead and only load classes when needed.

It works for static classes too, so once the static class is in scope, it doesn't need to even call the "is file included yet" test of require once, because the Class is already in the symbol table.

Then you can just create

require("autoloader.php"); 
$x = new Car();  
$x = new Bike();

and it will just bring them in when needed.

See Php.net/__autoload for more details.

Kent Fredric
Is autoload a syntactic sugar such that requires aren't locally scoped?
thesmart
When the file "required" contains class definitions, there is no issue with local scope. PHP does not support "inner classes" like Java; all classes are defined at the "top level" of the current namespace.
Bill Karwin
+1  A: 

Take a look to the __autoload() function.

Davide Gualano
+2  A: 

I would recommend using the autoloader.

That is, don't use require_once() to require either subclass, but allows the autoloader to call a function which can load the referenced class when you call new Truck() or new Car().

As for the memory leak question, no, require_once is not scoped by the code block.

Bill Karwin
A: 

The point of the require_once function is that no matter the scope, you won't include a file twice and redefine a class causing a PHP error. So no worries about memory leaks, if the require_once is hit, the class def goes in the global symbol table only one time.

But aside from that, yeah use autoloader.

Zak