Dynamically Create PHP Object Based on String

Dynamically create PHP object based on string

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;
}

How to dynamically instantiate an object in PHP?

You have to overload some other magic methods:

  • __get (a method that gets called when you call object member)
  • __set (a method that gets called when you want to set object member)
  • __isset
  • __unset

Please see this codepad to see your code rewritten to work with what you want:

<?php
class MyClass{
var $properties = array();

public function __construct($args){
$this->properties = $args;
}

public function __get($name) {
echo "Getting '$name'\n";
if (array_key_exists($name, $this->properties)) {
return $this->properties[$name];
}
return null;
}
}

$args = array("key1" => "value1", "key2" => "value2");
$class = "MyClass";
$obj = new $class($args);
echo "key1:". $obj->key1;
?>

laravel 5.1 - Dynamically create Class object based on string

When creating PHP objects with strings, you must provide the full qualified name of the class (a.k.a include the namespace). So, you should have something like this:

$className = 'App\\Http\\API\\' . $source;

$controller = new $className;

return $controller->index();

Another way to do it, if you are sure that the class you want to instantiate lives in the same namespace as your code, you can use:

$className = __NAMESPACE__ . '\\' . $source;

$controller = new $className;

return $controller->index();

A more elaborated way of achieving the same results is through the Factory Design Pattern. Basically you create a class that is responsible for instantiating elements, and you delegate the task of actually creating those objects to that class. Something along those lines:

class Factory {
function __construct ( $namespace = '' ) {
$this->namespace = $namespace;
}

public function make ( $source ) {
$name = $this->namespace . '\\' . $source;

if ( class_exists( $name ) ) {
return new $name();
}
}
}

$factory = new Factory( __NAMESPACE__ );

$controller = $factory->make( $source );

The advantage of this approach is that the responsability of creating the objects now lies in the Factory, and if you ever need to change it, maybe allow for aliases, add some additional security measures, or any other thing, you just need to change that code in one place, but as long as the class signature remains, your code keeps working.

An interesting tutorial on factories:
http://culttt.com/2014/03/19/factory-method-design-pattern/

Source:
http://nl3.php.net/manual/en/language.oop5.basic.php#language.oop5.basic.new
http://php.net/manual/en/language.namespaces.nsconstants.php

How to create new property dynamically

There are two methods to doing it.

One, you can directly create property dynamically from outside the class:

class Foo{

}

$foo = new Foo();
$foo->hello = 'Something';

Or if you wish to create property through your createProperty method:

class Foo{
public function createProperty($name, $value){
$this->{$name} = $value;
}
}

$foo = new Foo();
$foo->createProperty('hello', 'something');

How do I dynamically write a PHP object property name?

Update for PHP 7.0

PHP 7 introduced changes to how indirect variables and properties are handled at the parser level (see the corresponding RFC for more details). This brings actual behavior closer to expected, and means that in this case $obj->$field[0] will produce the expected result.

In cases where the (now improved) default behavior is undesired, curly braces can still be used to override it as shown below.

Original answer

Write the access like this:

$obj->{$field}[0]

This "enclose with braces" trick is useful in PHP whenever there is ambiguity due to variable variables.

Consider the initial code $obj->$field[0] -- does this mean "access the property whose name is given in $field[0]", or "access the element with key 0 of the property whose name is given in $field"? The braces allow you to be explicit.

Dynamically instantiating a class based on string in PHP

Try something like this...

foreach ($fields as $field) {
$type = $field['type'];

// instantiate the correct field class here based on type
$classname = 'form_field_' .$type;
if (!class_exists($classname)) { //continue or throw new Exception }

// functional
$new_field = new $classname();

// object oriented
$class = new ReflectionClass($classname);
$new_field = $class->newInstance();

$new_field->display();
}

How can I build a dynamic array from a string in PHP?

You're not using the repetition count at all from what I see. Achieving this using a straight-forward approach is tricky and probably not necessary when there's a simpler way to do this.

<?php
function buildReps($string) {
$array = [];
$overall_types = array( );
$types = explode( ',', $string );
foreach ($types as $type) {
$qc = explode( '|', $type );
$array = array_merge($array, array_fill(0, $qc[1], $qc[0]));
}
return $array;
}

function buildAllReps($string, $quantity) {
$array = [];

while (count($array) < $quantity) {
$array = array_merge($array, buildReps($string));
}
return array_slice($array, 0, $quantity);
}

$quantity = 10;
$string = '1|3,2|3';

echo '<pre>';
print_r ( buildAllReps($string, $quantity) );
echo '</pre>';

The first function builds the array once based on the $string defintion. The second one just merges the results from the first one until you reach quantity and then stops and returns the correct quantity of items back.

The above outputs:

Array
(
[0] => 1
[1] => 1
[2] => 1
[3] => 2
[4] => 2
[5] => 2
[6] => 1
[7] => 1
[8] => 1
[9] => 2
)

Example in https://eval.in/629556

Beware of infinite loops which may occur if the definition supplied by $string does not produce a non-empty array.

How do you access a dynamic property in an object?

This won't work in PHP < 7.2.0 and the issue is that the string-integer array keys are actually converted to integer property names, not strings. An alternate way to get an object from an array that will work:

$var = json_decode(json_encode(array('1' => 'Object one','2' => 'Object two')));
$num = "2";
var_dump( $var->$num );

See the Demo, in PHP < 7.2.0 the (object) cast converts to integer properties but json_decode creates string properties.

PHP: how to resolve a dynamic property of an object that is multiple levels deep

PHP doesn't automatically resolve a string containing multiple path levels to children of an object like you are attempting to do.

This will not work even if $obj contains the child hierarchy you are expecting:

$obj = ...;  
$path = 'level1->level2->level3';
echo $obj->$path; // WRONG!

You would need to split up the path and "walk" through the object trying to resolve the final property.
Here is an example based on yours:

<?php
$obj = new stdClass();
$obj->name = 'Fred';
$obj->job = new stdClass();
$obj->job->position = 'Janitor';
$obj->job->years = 4;
print_r($obj);

echo 'Years in current job: '.string($obj, 'job->years').PHP_EOL;

function string($obj, $path_str)
{
$val = null;

$path = preg_split('/->/', $path_str);
$node = $obj;
while (($prop = array_shift($path)) !== null) {
if (!is_object($obj) || !property_exists($node, $prop)) {
$val = null;
break;

}
$val = $node->$prop;
// TODO: Insert any logic here for cleaning up $val

$node = $node->$prop;
}

return $val;
}

Here it is working: http://3v4l.org/9L4gc

Retrieve object variables with dynamic key strings

I'm assuming you know how to access an object/array properly, and are trying to dynamically generate the path to the value that you want. The following code will allow you to pass a string, and filter through an object for the multiple keys in that string.

<?php
$myObj = new StdClass;
$myObj->required = array(
"name_required" => 1,
"courses" => array(
"course_name_required" => 1,
"lessons_required" => 1,
"lessons" => array(
"lesson_name_required" => 1,
"lesson_file_required" => 1,
"is_viewed_required" => 1,
),
),
);
// Desired Key I want to retrieve using dynamic strings.
$desiredKeyArrayPart = "[courses][lessons][lesson_name_required]";
$desiredKeyAttributePart = "required";

// Set our searchObject to $myObj->required using Variable Variables
$searchObject = $myObj->$desiredKeyAttributePart;
// Match all of the keys in our string
preg_match_all('/\[(.*?)\]/', $desiredKeyArrayPart, $keyMap);
// Foreach key that we found
foreach ($keyMap[1] as $key) {
// Change our $searchObject to the new key's value
$searchObject = $searchObject[$key];
}
// We found our object
var_dump($searchObject);


Related Topics



Leave a reply



Submit