James James - 3 months ago 18
PHP Question

Dynamic methods with parameters typing in PHP

I have the PHP legacy code below that intends to return the name of a method dynamically.

public function getMethod($fieldName){
//do stuff
return $methodName;
}


The returned method names are something like:


setClient

setName

setAge


All right here.
The problem is when I use these methods. I have a class named Model, that has the folowing method:

class Model {
public function find () {
$nameClass = get_called_class();
$instance = new $nameClass;

$result = $this->conn->select();//the select method returns a SQL SELECT from the database

if (isset($result[0])) {
foreach ($result[0] as $key => $val) {
$methodProp = $this->getMethod(key);
$instance->$methodProp($val);
}
} else {
throw new Exception('You have a error in your class');
}
}

}


Here is the
var_dump($result)
as requested:

array (size=1)
0 =>
object(stdClass)[6]
public 'id' => string '1' (length=1)
public 'id_erp' => string '0' (length=1)
public 'name' => string 'Derp' (length=18)
public 'email' => null
public 'type_ota' => null
public 'user' => string 'derp_derp' (length=7)
public 'password' => string '1234' (length=4)
public 'url_logo' => null
public 'status' => string '1' (length=1)
public 'date' => string '2015-06-08 14:41:50' (length=19)


Then I have some classes that extends this Model:

class Company extends Model {
public function setClient (Client $cli) {
//do stuff
}
public function setName($name) {
//do stuff
}
public function setAge($age) {
//do stuff
}
}
//here I use the class
$myCompany = new Company();
$myCompany->find();


The methods
setName()
and
setAge()
works fine, but
setClient()
returns


Catchable fatal error: Argument 1 passed to setClient() must be an instance of Client, string given


In short, how can I deal with dynamic methods and typing in PHP?
Looking for help, I found something about Reflection, but I never used this class before and the examples that I found didn't help me, although I think that it's the right way.

Has anyone had a similar experience?

UPDATE

I tried to put some code in my question to clarify my problem.

Answer

If I understand your question correctly, you want to check what typehint the method wants. I took this code snippet from the docs.

<?php
//Target our class
$reflector = new ReflectionClass('MyClass');

//Get the parameters of a method
$parameters = $reflector->getMethod('FireCannon')->getParameters();

//Loop through each parameter and get the type
foreach($parameters as $param)
{
     //Before you call getClass() that class must be defined!
     echo $param->getClass()->name;
}

To add the code above to your code. This would check if the parameter in the method is an object, if is an object it will check that the class is the same as the value given. If the parameter is not an object, you can either just call the method, or if you typehint your non-object parameters, you can check that they are equal as well. This code should definitely be modified and cleaned up, but I thought it would be enough to get my point across.

class Model {
    public function find () {
        $nameClass = get_called_class();
        $instance  = new $nameClass;

        $result = $this->conn->select();//the select method returns a SQL SELECT from the database

        if (!isset($result[0])) {
            throw new Exception('You have a error in your class');
        }
        foreach ($result[0] as $key => $val) {
            $methodProp = $this->getMethod($key);

            $reflector = new ReflectionClass($nameClass);
            $reflectorMethod = $reflector->getMethod($methodProp);

            // Make sure method doesn't require more than one param,
            // and it has defined at least one param.
            if ($reflectorMethod->getNumberOfRequiredParameters() > 1 ||
                $reflectorMethod->getNumberOfParameters() < 1
            ) {
                // Throw error
            }

            //Get the parameters of a method
            $parameters = $reflectorMethod->getParameters();

           if (is_object($parameters[0])) {
               if (!is_object($val) {
                   // Throw error
               }
               //Before you call get_class() that class must be defined!
               //Use either class_exists($nameClass); or 
               //in_array($nameClass, get_declared_classes()); to check.
               if ($val->getClass()->name !== get_class($parameters[0])) {
                   // Throw error
               }
           } else if (gettype($parameters[0]) !== gettype($val)) {
               // Throw error
           }
           $instance->$methodProp($val);
        }
    }
}
Comments