2010-12-22 9 views
11

Estoy tratando de usar reflexión PHP para cargar dinámicamente los archivos de clase de los modelos en función del tipo de parámetro que está en el método del controlador. Aquí hay un ejemplo de método de control.Reflexión de PHP - Obtener método Parámetro Tipo como cadena

<?php 

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

Esto es lo que tengo hasta ahora.

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

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

Esto funciona, y la salida sería 'SteelSlugModel', como se esperaba. Sin embargo, existe la posibilidad de que el archivo de clase del modelo no se haya cargado todavía, y el uso de getClass() requiere que se defina la clase. Parte de por qué lo hago es cargar automáticamente cualquier modelo que requiera una acción de controlador. .

¿Hay alguna manera de obtener el nombre del tipo de parámetro sin tener que cargar primero el archivo de clase?

+0

¿Qué es '$ p'? ¿Te refieres a '$ param'? –

+0

A menos que la clase Reflection carezca de una información vital en sus documentos, no creo que pueda obtener el tipo insinuado sin tener cargada la clase. – simshaun

+0

@simshaun: No. La clase necesita ser cargada, de lo contrario 'getClass' arroja' ReflectionException'. – netcoder

Respuesta

8

Creo que la única manera de hacerlo es export y manipular la cadena de resultado:

$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; 
+1

Esto funciona, aunque realmente me gustaría poder evitar tener que analizar una cadena para hacerlo. Buen trabajo. –

+0

¿Sigue siendo esta la única forma de hacer esto? ¡Tener que confiar en el formato de salida no estándar del método de exportación es incompleto! – dellsala

1

tuve problema similar, al comprobar getClass el parámetro de reflexión cuando una clase no estaba cargada. Hice una función de contenedor para obtener el nombre de clase del netcoder de ejemplo creado. El problema era que el código de netcoder no funcionaba si era una matriz o no una clase -> función ($ test) {} devolvía el método de cadena al parámetro de reflexión.

Debajo de la manera en que lo resolví, estoy usando try catch porque mi código requiere en algún momento la clase. Entonces, si lo solicito la próxima vez, la clase funciona y no lanza una excepción.

/** 
* 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; 
} 
+0

También está en php.net bugs -> https://bugs.php.net/bug.php?id=32177&edit=1 – daanl

+0

Esta función no necesita perder tiempo usando preg_match. (También falla el parámetro no tiene una sugerencia de clase). Ver mi ejemplo actualizado: https: //gist.github.com/Xeoncross/4723819 – Xeoncross

4

Usted podría utilizar Zend Framework 2.

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

foreach($method_reflection->getParameters() as $reflection_parameter) 
{ 
    $type = $reflection_parameter->getType(); 
} 
+1

La función 'getType' no existe enymore, ahora se llama' getClass'. –

7

supone que esto es lo que busca:

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(); 
} 
+0

Usar la API de reflexión actual esta es la mejor solución y debería ser la respuesta aceptada. –

+0

'getClass()' genera un error cuando una firma de método contiene sugerencias de tipo como "cadena" o "matriz". Y el tipo "cadena" no se puede detectar en PHP <7. – powtac

1

getType método se puede utilizar a partir de 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() 
); 
0

Esta es una expresión regular mejor que la de that answer. Funcionará incluso cuando el parámetro sea opcional.

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