14

I'm trying to use PHP reflection to dynamically load the class files of models automatically based upon the type of parameter that is in the controller method. Here's an example controller method.

<?php

class ExampleController
{
    public function PostMaterial(SteelSlugModel $model)
    {
        //etc...
    }
}

Here's what I have so far.

//Target the first parameter, as an example
$param = new ReflectionParameter(array('ExampleController', 'PostMaterial'), 0);

//Echo the type of the parameter
echo $param->getClass()->name;

This works, and the output would be 'SteelSlugModel', as expected. However, there is the possibility that the class file of the model may not be loaded yet, and using getClass() requires that the class be defined - part of why I'm doing this is to autoload any models that a controller action may require.

Is there a way to get the name of the parameter type without having to load the class file first?

5
  • What is $p? Do you mean $param? Commented Dec 22, 2010 at 21:33
  • Unless the Reflection class is lacking a vital piece of information in its docs, I don't think you can get the hinted type without having the class loaded.
    – simshaun
    Commented Dec 22, 2010 at 21:41
  • @simshaun: No. The class needs to be loaded, otherwise getClass throws a ReflectionException.
    – netcoder
    Commented Dec 22, 2010 at 21:45
  • @netcoder, I know that about getClass. I was essentially saying "unless there is another way of getting the hinted type that I'm not aware of or could not find in the docs"
    – simshaun
    Commented Dec 22, 2010 at 21:47
  • @Rafe - yes, $p was supposed to be $param. Fixed in the code. Commented Dec 22, 2010 at 21:56

6 Answers 6

15

I supposed this is what you are looking for:

class MyClass {

    function __construct(AnotherClass $requiredParameter, YetAnotherClass $optionalParameter = null) {
    }

}

$reflector = new ReflectionClass("MyClass");

foreach ($reflector->getConstructor()->getParameters() as $param) {
    // param name
    $param->name;

    // param type hint (or null, if not specified).
    $param->getClass()->name;

    // finds out if the param is required or optional
    $param->isOptional();
}
2
  • Using current reflection API this is the best solution and should be the accepted answer.
    – Maciej Sz
    Commented Mar 30, 2015 at 12:16
  • getClass() leads to error when a method signature contains type hinting like "string" or "array". And type "string" can't be detected on PHP < 7.
    – powtac
    Commented Dec 13, 2016 at 16:33
12

I think the only way is to export and manipulate the result string:

$refParam = new ReflectionParameter(array('Foo', 'Bar'), 0);

$export = ReflectionParameter::export(
   array(
      $refParam->getDeclaringClass()->name, 
      $refParam->getDeclaringFunction()->name
   ), 
   $refParam->name, 
   true
);

$type = preg_replace('/.*?(\w+)\s+\$'.$refParam->name.'.*/', '\\1', $export);
echo $type;
3
  • 1
    This works, although I truly wish I could avoid having to parse a string to do it. Good work. Commented Dec 27, 2010 at 14:09
  • Is this still the only way to do this? Having to rely on the export method's non-standard output format is sketchy!
    – dellsala
    Commented Oct 4, 2012 at 14:26
  • export is deprecated php.net/manual/en/reflectionmethod.export.php
    – soyuka
    Commented Mar 28, 2023 at 21:54
5

getType method can be used since PHP 7.0.

class Foo {}
class Bar {}

class MyClass
{
    public function baz(Foo $foo, Bar $bar) {}
}

$class = new ReflectionClass('MyClass');
$method = $class->getMethod('baz');
$params = $method->getParameters();

var_dump(
    'Foo' === (string) $params[0]->getType()
);
4

You could use Zend Framework 2.

$method_reflection = new \Zend\Code\Reflection\MethodReflection( 'class', 'method' );

foreach( $method_reflection->getParameters() as $reflection_parameter )
{
  $type = $reflection_parameter->getType();
}
1
  • 2
    The function getTypeis not existing enymore, it's now called getClass. Commented Nov 9, 2012 at 13:26
1

I had similar problem, when checking getClass on reflection parameter when a class was not loaded. I made a wrapper function to get the class name from example netcoder made. Problem was that netcoder code didnt work if it was an array or not an class -> function($test) {} it would return the to string method for the reflection parameter.

Below the way how i solved it, im using try catch because my code requires at some point the class. So if i request it the next time, get class works and doesnt throw an exception.

/**
 * Because it could be that reflection parameter ->getClass() will try to load an class that isnt included yet
 * It could thrown an Exception, the way to find out what the class name is by parsing the reflection parameter
 * God knows why they didn't add getClassName() on reflection parameter.
 * @param ReflectionParameter $reflectionParameter
 * @return string Class Name
 */
public function ResolveParameterClassName(ReflectionParameter $reflectionParameter)
{
    $className = null;

    try
    {
                 // first try it on the normal way if the class is loaded then everything should go ok
        $className = $reflectionParameter->getClass()->name;

    }
    // if the class isnt loaded it throws an exception and try to resolve it the ugly way
    catch (Exception $exception)
    {
        if ($reflectionParameter->isArray())
        {
            return null;
        }

        $reflectionString = $reflectionParameter->__toString();
        $searchPattern = '/^Parameter \#' . $reflectionParameter->getPosition() . ' \[ \<required\> ([A-Za-z]+) \$' . $reflectionParameter->getName() . ' \]$/';

        $matchResult = preg_match($searchPattern, $reflectionString, $matches);

        if (!$matchResult)
        {
            return null;
        }

        $className = array_pop($matches);
    }

    return $className;
}
1
  • This function doesn't need to waste time using preg_match. (It also fails of the parameter doesn't have a class hint). See my updated example: gist.github.com/Xeoncross/4723819
    – Xeoncross
    Commented Feb 6, 2013 at 16:36
0

This is a better regular expression than the one from that answer. It will work even when the parameter is optional.

preg_match('~>\s+([a-z]+)\s+~', (string)$ReflectionParameter, $result);
$type = $result[1];

Not the answer you're looking for? Browse other questions tagged or ask your own question.