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
PHP Random Shuffle Array Maintaining Key => Value
What Can Use for Datetime::Diff() for PHP 5.2
How to Sort an Array of Utf-8 Strings in PHP
Object of Class Datetime Could Not Be Converted to String
How to Select Randomly with Doctrine
Best Way to Transfer an Array Between PHP and JavaScript
How to Send Emails via Cron Job Usng PHP MySQL
Fix Malformed Xml in PHP Before Processing Using Domdocument Functions
How to Create Codeigniter Batch Insert Array
MySQL No Connection Could Be Made Because the Target MAChine Actively Refused It
Hide Shipping Methods for Specific Shipping Class in Woocommerce
Preg_Match(); - Unknown Modifier '+'
Php: How to Explode a String by Commas, But Not Wheres the Commas Are Within Quotes