Skip to content

Commit

Permalink
[6.x] Support PHP 8's reflection API (#33039)
Browse files Browse the repository at this point in the history
* Support PHP 8's reflection API

* Fixes
  • Loading branch information
GrahamCampbell authored Jun 1, 2020
1 parent 744d01d commit 1af0632
Show file tree
Hide file tree
Showing 11 changed files with 87 additions and 26 deletions.
2 changes: 1 addition & 1 deletion src/Illuminate/Auth/Access/Gate.php
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,7 @@ protected function callbackAllowsGuests($callback)
*/
protected function parameterAllowsGuests($parameter)
{
return ($parameter->getClass() && $parameter->allowsNull()) ||
return ($parameter->hasType() && $parameter->allowsNull()) ||
($parameter->isDefaultValueAvailable() && is_null($parameter->getDefaultValue()));
}

Expand Down
9 changes: 5 additions & 4 deletions src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Illuminate\Contracts\Routing\BindingRegistrar;
use Illuminate\Contracts\Routing\UrlRoutable;
use Illuminate\Support\Arr;
use Illuminate\Support\Reflector;
use Illuminate\Support\Str;
use ReflectionClass;
use ReflectionFunction;
Expand Down Expand Up @@ -204,9 +205,9 @@ protected function resolveImplicitBindingIfPossible($key, $value, $callbackParam
continue;
}

$instance = $parameter->getClass()->newInstance();
$className = Reflector::getParameterClassName($parameter);

if (! $model = $instance->resolveRouteBinding($value)) {
if (is_null($model = (new $className)->resolveRouteBinding($value))) {
throw new AccessDeniedHttpException;
}

Expand All @@ -225,8 +226,8 @@ protected function resolveImplicitBindingIfPossible($key, $value, $callbackParam
*/
protected function isImplicitlyBindable($key, $parameter)
{
return $parameter->name === $key && $parameter->getClass() &&
$parameter->getClass()->isSubclassOf(UrlRoutable::class);
return $parameter->getName() === $key &&
Reflector::isParameterSubclassOf($parameter, UrlRoutable::class);
}

/**
Expand Down
20 changes: 12 additions & 8 deletions src/Illuminate/Container/BoundMethod.php
Original file line number Diff line number Diff line change
Expand Up @@ -157,16 +157,20 @@ protected static function getCallReflector($callback)
protected static function addDependencyForCallParameter($container, $parameter,
array &$parameters, &$dependencies)
{
if (array_key_exists($parameter->name, $parameters)) {
$dependencies[] = $parameters[$parameter->name];
if (array_key_exists($parameter->getName(), $parameters)) {
$paramName = $parameter->getName();

unset($parameters[$parameter->name]);
} elseif ($parameter->getClass() && array_key_exists($parameter->getClass()->name, $parameters)) {
$dependencies[] = $parameters[$parameter->getClass()->name];
$dependencies[] = $parameters[$paramName];

unset($parameters[$parameter->getClass()->name]);
} elseif ($parameter->getClass()) {
$dependencies[] = $container->make($parameter->getClass()->name);
unset($parameters[$paramName]);
} elseif (! is_null($className = Util::getParameterClassName($parameter))) {
if (array_key_exists($className, $parameters)) {
$dependencies[] = $parameters[$className];

unset($parameters[$className]);
} else {
$dependencies[] = $container->make($className);
}
} elseif ($parameter->isDefaultValueAvailable()) {
$dependencies[] = $parameter->getDefaultValue();
}
Expand Down
8 changes: 4 additions & 4 deletions src/Illuminate/Container/Container.php
Original file line number Diff line number Diff line change
Expand Up @@ -846,7 +846,7 @@ public function build($concrete)
/**
* Resolve all of the dependencies from the ReflectionParameters.
*
* @param array $dependencies
* @param \ReflectionParameter[] $dependencies
* @return array
*
* @throws \Illuminate\Contracts\Container\BindingResolutionException
Expand All @@ -868,7 +868,7 @@ protected function resolveDependencies(array $dependencies)
// If the class is null, it means the dependency is a string or some other
// primitive type which we can not resolve since it is not a class and
// we will just bomb out with an error since we have no-where to go.
$results[] = is_null($dependency->getClass())
$results[] = is_null(Util::getParameterClassName($dependency))
? $this->resolvePrimitive($dependency)
: $this->resolveClass($dependency);
}
Expand Down Expand Up @@ -920,7 +920,7 @@ protected function getLastParameterOverride()
*/
protected function resolvePrimitive(ReflectionParameter $parameter)
{
if (! is_null($concrete = $this->getContextualConcrete('$'.$parameter->name))) {
if (! is_null($concrete = $this->getContextualConcrete('$'.$parameter->getName()))) {
return $concrete instanceof Closure ? $concrete($this) : $concrete;
}

Expand All @@ -942,7 +942,7 @@ protected function resolvePrimitive(ReflectionParameter $parameter)
protected function resolveClass(ReflectionParameter $parameter)
{
try {
return $this->make($parameter->getClass()->name);
return $this->make(Util::getParameterClassName($parameter));
}

// If we can not resolve the class instance, we will check to see if the value
Expand Down
15 changes: 15 additions & 0 deletions src/Illuminate/Container/Util.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,19 @@ public static function unwrapIfClosure($value)
{
return $value instanceof Closure ? $value() : $value;
}

/**
* Get the class name of the given parameter's type, if possible.
*
* From Reflector::getParameterClassName() in Illuminate\Support.
*
* @param \ReflectionParameter $parameter
* @return string|null
*/
public static function getParameterClassName($parameter)
{
$type = $parameter->getType();

return ($type && ! $type->isBuiltin()) ? $type->getName() : null;
}
}
4 changes: 2 additions & 2 deletions src/Illuminate/Foundation/Console/ClosureCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ protected function execute(InputInterface $input, OutputInterface $output)
$parameters = [];

foreach ((new ReflectionFunction($this->callback))->getParameters() as $parameter) {
if (isset($inputs[$parameter->name])) {
$parameters[$parameter->name] = $inputs[$parameter->name];
if (isset($inputs[$parameter->getName()])) {
$parameters[$parameter->getName()] = $inputs[$parameter->getName()];
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/Illuminate/Foundation/Events/DiscoverEvents.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Illuminate\Foundation\Events;

use Illuminate\Support\Reflector;
use Illuminate\Support\Str;
use ReflectionClass;
use ReflectionException;
Expand Down Expand Up @@ -58,7 +59,7 @@ protected static function getListenerEvents($listeners, $basePath)
}

$listenerEvents[$listener->name.'@'.$method->name] =
optional($method->getParameters()[0]->getClass())->name;
Reflector::getParameterClassName($method->getParameters()[0]);
}
}

Expand Down
5 changes: 3 additions & 2 deletions src/Illuminate/Routing/ImplicitRouteBinding.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Illuminate\Contracts\Routing\UrlRoutable;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Reflector;
use Illuminate\Support\Str;

class ImplicitRouteBinding
Expand All @@ -22,7 +23,7 @@ public static function resolveForRoute($container, $route)
$parameters = $route->parameters();

foreach ($route->signatureParameters(UrlRoutable::class) as $parameter) {
if (! $parameterName = static::getParameterName($parameter->name, $parameters)) {
if (! $parameterName = static::getParameterName($parameter->getName(), $parameters)) {
continue;
}

Expand All @@ -32,7 +33,7 @@ public static function resolveForRoute($container, $route)
continue;
}

$instance = $container->make($parameter->getClass()->name);
$instance = $container->make(Reflector::getParameterClassName($parameter));

if (! $model = $instance->resolveRouteBinding($parameterValue)) {
throw (new ModelNotFoundException)->setModel(get_class($instance), [$parameterValue]);
Expand Down
7 changes: 4 additions & 3 deletions src/Illuminate/Routing/RouteDependencyResolverTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Illuminate\Routing;

use Illuminate\Support\Arr;
use Illuminate\Support\Reflector;
use ReflectionFunctionAbstract;
use ReflectionMethod;
use ReflectionParameter;
Expand Down Expand Up @@ -68,15 +69,15 @@ public function resolveMethodDependencies(array $parameters, ReflectionFunctionA
*/
protected function transformDependency(ReflectionParameter $parameter, $parameters)
{
$class = $parameter->getClass();
$className = Reflector::getParameterClassName($parameter);

// If the parameter has a type-hinted class, we will check to see if it is already in
// the list of parameters. If it is we will just skip it as it is probably a model
// binding and we do not want to mess with those; otherwise, we resolve it here.
if ($class && ! $this->alreadyInParameters($class->name, $parameters)) {
if ($className && ! $this->alreadyInParameters($className, $parameters)) {
return $parameter->isDefaultValueAvailable()
? $parameter->getDefaultValue()
: $this->container->make($class->name);
: $this->container->make($className);
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/Illuminate/Routing/RouteSignatureParameters.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Illuminate\Routing;

use Illuminate\Support\Reflector;
use Illuminate\Support\Str;
use ReflectionFunction;
use ReflectionMethod;
Expand All @@ -22,7 +23,7 @@ public static function fromAction(array $action, $subClass = null)
: (new ReflectionFunction($action['uses']))->getParameters();

return is_null($subClass) ? $parameters : array_filter($parameters, function ($p) use ($subClass) {
return $p->getClass() && $p->getClass()->isSubclassOf($subClass);
return Reflector::isParameterSubclassOf($p, $subClass);
});
}

Expand Down
37 changes: 37 additions & 0 deletions src/Illuminate/Support/Reflector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

namespace Illuminate\Support;

use ReflectionClass;

class Reflector
{
/**
* Get the class name of the given parameter's type, if possible.
*
* @param \ReflectionParameter $parameter
* @return string|null
*/
public static function getParameterClassName($parameter)
{
$type = $parameter->getType();

return ($type && ! $type->isBuiltin()) ? $type->getName() : null;
}

/**
* Determine if the parameter's type is a subclass of the given type.
*
* @param \ReflectionParameter $parameter
* @param string $className
* @return bool
*/
public static function isParameterSubclassOf($parameter, $className)
{
$paramClassName = static::getParameterClassName($parameter);

return ($paramClassName && class_exists($paramClassName))
? (new ReflectionClass($paramClassName))->isSubclassOf($className)
: false;
}
}

0 comments on commit 1af0632

Please sign in to comment.