51

I would like to create an object in PHP based on a type defined by a string in a MySQL database. The database table has columns and sample data of:

 id | type | propertyVal
----+------+-------------
  1 | foo  | lorum
  2 | bar  | ipsum

...with PHP data types

class ParentClass {...}
class Foo extends ParentClass {private $id, $propertyVal; ...}
class Bar extends ParentClass {private $id, $propertyVal; ...} 
//...(more classes)...

Using only one query, I would like to SELECT a row by id and create an object of the type define the table's type column with other columns in the SELECTed row being assigned to the newly created object.

I was thinking that using:

  1. mysql_fetch_object()
  2. Reading the type attribute
  3. Creating an object with type defined by type attribute

But know of no way to dynamically create a type based on a string. How does one do this?

5 Answers 5

117

But know of no way to dynamically create a type based on a string. How does one do this?

You can do it quite easily and naturally:

$type = 'myclass';

$instance = new $type;

If your query is returning an associative array, you can assign properties using similar syntax:

// build object
$type = $row['type'];
$instance = new $type;

// remove 'type' so we don't set $instance->type = 'foo' or 'bar'
unset($row['type']);  

// assign properties
foreach ($row as $property => $value) {
   $instance->$property = $value;
}
Sign up to request clarification or add additional context in comments.

2 Comments

You can also pass arguments to the constructor $instance = new $type(5, 'hi');
note that className must be a full-path, valid address of class, for example: ` $type = "app\models\MyClass"; `
10

There's a very neat syntax you can use that I learned about a couple of months ago that does not rely on a temporary variable. Here's an example where I use a POST variable to load a specific class:

$eb = new ${!${''} = $_POST['entity'] . 'Binding'}();

In your specific case though, you would be able to solve it by using PDO. It has a fetch mode that allows the first column's value to be the class the row instantiates into.

$sth->fetch(PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE);

3 Comments

I don't get it, apparently you would get $eb= new ${FALSE}(); or am I missing something??
The reason this hack works is because ${false} evaluates to ${''} (same thing as writing (string)false) and the variable with the name [empty string] is the one we just created in the inner bracket clause. Very nifty.
What is the name of this syntax? Where can I read more about it? Because I am not understanding it.
8
$instance = new $classname; // i.e. $type in your case

Works very well...

1 Comment

But then how do you add the arguments of the constructor? Is it valid to do: $instance = new $classname($parameterA, $parameterB);
2

Below is what I was looking for when I came to this thread. use {"objectName"} (brackets) to declare or reference the object name in the form of a string.

$gameData = new stdClass();
$gameData->location = new stdClass();
$basementstring = "basement";

class tLocation {
    public $description;
}

$gameData->location->{'darkHouse'} = new tLocation;
$gameData->location->{"darkHouse"}->description = "You walkinto a dusty old house";


$gameData->location->{$basementstring} = new tLocation;
$gameData->location->{"basement"}->description = "its really damp down here.";

//var_dump($gameData); 
echo $gameData->location->basement->description;

This way of referring to the object seems to be interchangeable. I couldn't find the answer so i had to fool around with it Until I found a way.

Comments

0

as silkfire says, this can be achieved by using PDO specific modes, so here is an example. Using your same database values and defined objects:

 id | type | propertyVal
----+------+-------------
  1 | foo  | lorum
  2 | bar  | ipsum

class ParentClass {...}
class Foo extends ParentClass {private $id, $propertyVal; ...}
class Bar extends ParentClass {private $id, $propertyVal; ...} 
//...(more classes)...

with a single query (you must name the field containing the class name first):

$stmt = $db->prepare('SELECT type,id,propertyVal FROM table WHERE id=1');
$stmt->execute();
$foo = $stmt->fetch(PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE);
var_dump($foo); // $foo is a newly created object of class foo, with properties named like and containing the value of subsequent fields

this is cool but it gets cooler with a while

$stmt = $db->prepare('SELECT type,id,propertyVal FROM table');
$stmt->execute();
while ($object = $stmt->fetch(PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE))
 {var_dump($object);} // here all desired objects, dynamically constructed accordingly to the first column returned by the query

you can define a constructor (which will be called after the values from database are assigned to properties) to work on those dynamically assigned properties, say by replacing a string with it's uppercased value

class foo
 {function __construct ()
   {$this->uper = strtoupper($this->propertyVal);}}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.