I wrote a dependency provider (basically IOC container) for my application. I added the feature of autowiring, although it hits a snag when the class it is trying to autowire doesn't have a constructor.
Uncaught Error: Call to a member function getParameters() on null in C:\xampp\htdocs\src\app\Providers\DependencyProvider.php:68
I am fairly certain it is trying to resolve constructor arguments in the resolveArguments method, on a class that doesn't have a constructor, and this is why the issue is happening.
So, resolveArguments should only be called if the class needs their arguments resolved (autowired), and that is usually only when it has a constructor.
The error message above, is happening because getConstructor is returning null. I am asking what is the best practice to check if a reflection class has a constructor that needs autowiring?
Full class:
<?php
namespace App\Providers;
class DependencyProvider {
private static $objects = [];
/**
* Register an instantiated object to the container.
*
* @param object $object
*/
public static function register(object $object) : void {
self::$objects[get_class($object)] = $object;
}
/**
* Fetch a cached object from the container.
*
* @param string $objectName
* @return object
*/
public static function fetch(string $objectName) : object {
if (array_key_exists($objectName, self::$objects)) {
return self::$objects[$objectName];
}
$object = self::make($objectName);
self::$objects[$objectName] = $object;
return $object;
}
/**
* Creates an object from its name and auto-wires constructor arguments.
*
* @param string $objectName
* @return object
* @throws \ReflectionException
*/
private static function make(string $objectName) : object {
$reflection = new \ReflectionClass($objectName);
if (!$reflection->isInstantiable()) {
throw new RuntimeException($reflection->getName() . ' can\'t be instantiated.');
}
$arguments = self::resolveArguments($reflection);
if (count($arguments) < 1) {
return $reflection->newInstance();
}
else {
return $reflection->newInstanceArgs($arguments);
}
}
/**
* Creates an array of arguments from a reflection class.
* Uses default value if there is one, auto-wires the object if not.
*
* @param $reflection
* @return array
*/
private static function resolveArguments($reflection) : array {
$constructor = $reflection->getConstructor();
$parameters = $constructor->getParameters();
if (!$parameters) {
return $reflection->newInstance();
}
$arguments = [];
foreach ($parameters as $parameter) {
if ($parameter->isDefaultValueAvailable()) {
$arguments[] = $parameter->getDefaultValue();
continue;
}
if ($parameter->getClass() == null) {
exit($parameter->name . ' on ' . $reflection->getName() . ' needs a default value');
}
$arguments[] = self::fetch($parameter->getClass()->getName());
}
return $arguments;
}
}