I am trying to turn an query result into classes.
$result->setFetchMode(PDO::FETCH_CLASS, 'myclass', array());
开发者_运维百科
This works quite well however the class name myclass
depends on the column values.
Is it possible to fetch each row and turn it into a different class depending on the rows values?
User example:
ID # name # age
1 # jon # 12
2 # sue # 23
3 # tom # 24
I want to have all users with an age less then 21 to be instances of the class child
.
Rows with age of 21 and above should be instances of the class adult
.
So "jon" should be an instance of child
.
"sue" and "tom" should be instances of adult
.
As you do not know the type (classname) of the returned objects before you do the query, you can not specify it.
However, you could encapsulate that logic inside another type you use as return type which can then return the specific return type:
/**
* Should not have any private, public or protected members in it's definition.
*
* Does only work for public properties.
*/
class ReturnObject {
public function getConcrete()
{
/* decide here which class */
$classname = 'Child'; // or 'Adult'
return $this->selfAs($classname);
}
private function selfAs($classname)
{
$l = strlen(__CLASS__);
$s = sprintf('O:%d:"%s"', strlen($classname), $classname).substr(serialize($this), 5+strlen($l)+$l);
$instance = unserialize($s);
$instance->__construct();
return $instance;
}
}
You can then use the getConcrete()
function on each returned object to return your specific type, your decision logic bound to the database return.
Edit: I changed it into a version that will first initialize the objects properties via unserialize (please test if this works, it's based on the assumption that we're talking about public properties only and I don't know if PDO just does the setters or more via reflection in the mode you're using) and then calls the constructor function. The constructor needs to be public (and it must exist) so that this works.
It's technically possible to make this available for private and protected members as well, however this needs real reflection and it as well needs parsing of the serialized data as well. This class only renames the classname, but not inside private properties.
However this is only one way for doing so. You probably only need a ->isChild()
or ->isAdult()
function on your Person
class.
This cant really be done automaticly, it is too specific. You can just loop over each row and instantiate the correct class with the proper arguments.
I would not use PDO::FETCH_CLASS for that. You can change your SQL to return class name based on value of age
SELECT
id,
name,
age,
CASE WHEN age < 21 THEN 'child'
ELSE 'adult' END
AS class_name
FROM SOME_TABLE";
Then use your PDO::FETCH_ASSOC as fetch type
Then when you loop over your results
you can easily instantiave class based on
$result['class_name'] like this:
$class = $result['class_name'];
$obj = new $class;
I think wich the best answer is here.
How to use PDO::FETCH_CLASS with abstract class?
精彩评论