Ad

Object Creation From Class Name Not Working Within Namespace

- 1 answer

I'm creating a factory class in my project, where this class gets a Report Type as a string. This string has the name of the concrete class that implements a Report Interface.

The issue I'm having is that when I'm instantiating this class, I get a Class not found error.

Here follows the factory code.

namespace App\Term\Reports;

class Factory
{
    public static function build($type)
    {
        $obj = new CableBySensor();  // Works!

        // $type == 'CableBySensor'
        $obj2 = new $type;         // Class not found :(

        // ... validates if the class exists ...
        // ... and if it implements the Report Interface ...
        // ... throw exception if class doesn't exist or doesn't implements interface
        // ... then returns the corresponding object.
    }
}

Both methods are virtually the same thing.

First: Why do I have to specify the full qualified name of the class in the string to make it work? The class CableBySensor resides in the same namespace as Factory.

This started giving me trouble because I also want to validate that the class being instantiated implements a ReportsInterface.

Second: How do I overcome this? Should I call the factory like this $myReport = Factory::build('App\Term\Reports\' . $className); or should I use the __NAMESPACE__ constant inside the Factory class such as this: $obj = new __NAMESPACE__ . '\' . $className?

Thank you.

Ad

Answer

Indifferently whether the factory approach is useful here or not, the problem is with trying to instantiate from a dynamic variable.

Or as akhoondi at php.net pointed out:

One must note that when using a dynamic class name [...] the "current namespace" [...] is global namespace.

There are possibly 3 solutions:

  • pass the fully qualified class name to your factory method (arghh...)

    $instance = Factory::build('Acme\CableBySensor');
    
  • Or, do a check in your build method and prefix the namespace if necessary (as suggested here) (sounds not so fool proof to me)

    public static function build($type)
    {
        if ($type[0] !== '\\') {
            $type = '\\' . __NAMESPACE__ . '\\' . $type;
        }
        $obj = new $type;
        ...
    }
    
  • Or, if you have PHP 5.5+ why not use class name resolution via ::class? Personally, I would go for that one whenever possible:

    $instance = Factory::build(CableBySensor::class);
    
Ad
source: stackoverflow.com
Ad