I have two classes, class ClassOne { } and class ClassTwo {}. I am getting a string which can be either "One" or "Two".
Instead of using a long switch statement such as:
switch ($str) {
case "One":
return new ClassOne();
case "Two":
return new ClassTwo();
}
Is there a way I can create an instance using a string, i.e. new Class("Class" . $str);?
Yes, you can!
$str = 'One';
$class = 'Class'.$str;
$object = new $class();
When using namespaces, supply the fully qualified name:
$class = '\Foo\Bar\MyClass';
$instance = new $class();
Other cool stuff you can do in php are:
Variable variables:
$personCount = 123;
$varname = 'personCount';
echo $$varname; // echo's 123
And variable functions & methods.
$func = 'my_function';
$func('param1'); // calls my_function('param1');
$method = 'doStuff';
$object = new MyClass();
$object->$method(); // calls the MyClass->doStuff() method.
You can simply use the following syntax to create a new class (this is handy if you're creating a factory):
$className = $whatever;
$object = new $className;
As an (exceptionally crude) example factory method:
public function &factory($className) {
require_once($className . '.php');
if(class_exists($className)) return new $className;
die('Cannot create new "' . $className . '" class - includes not found or class unavailable.');
}
have a look at example 3 from http://www.php.net/manual/en/language.oop5.basic.php
$className = 'Foo';
$instance = new $className(); // Foo()
Lets say ClassOne is defined as:
public class ClassOne
{
protected $arg1;
protected $arg2;
//Contructor
public function __construct($arg1, $arg2)
{
$this->arg1 = $arg1;
$this->arg2 = $arg2;
}
public function echoArgOne
{
echo $this->arg1;
}
}
Using PHP Reflection;
$str = "One";
$className = "Class".$str;
$class = new \ReflectionClass($className);
Create a new Instance:
$instance = $class->newInstanceArgs(["Banana", "Apple")]);
Call a method:
$instance->echoArgOne();
//prints "Banana"
Use a variable as a method:
$method = "echoArgOne";
$instance->$method();
//prints "Banana"
Using Reflection instead of just using the raw string to create an object gives you better control over your object and easier testability (PHPUnit relies heavily on Reflection)
// Way #1
$className = "App\MyClass";
$instance = new $className();
// Way #2
$className = "App\MyClass";
$class = new \ReflectionClass($className);
// Create a new Instance without arguments:
$instance = $class->newInstance();
// Create a new Instance with arguments (need a contructor):
$instance = $class->newInstanceArgs(["Banana", "Apple"]);
Related
I have two classes, class ClassOne { } and class ClassTwo {}. I am getting a string which can be either "One" or "Two".
Instead of using a long switch statement such as:
switch ($str) {
case "One":
return new ClassOne();
case "Two":
return new ClassTwo();
}
Is there a way I can create an instance using a string, i.e. new Class("Class" . $str);?
Yes, you can!
$str = 'One';
$class = 'Class'.$str;
$object = new $class();
When using namespaces, supply the fully qualified name:
$class = '\Foo\Bar\MyClass';
$instance = new $class();
Other cool stuff you can do in php are:
Variable variables:
$personCount = 123;
$varname = 'personCount';
echo $$varname; // echo's 123
And variable functions & methods.
$func = 'my_function';
$func('param1'); // calls my_function('param1');
$method = 'doStuff';
$object = new MyClass();
$object->$method(); // calls the MyClass->doStuff() method.
You can simply use the following syntax to create a new class (this is handy if you're creating a factory):
$className = $whatever;
$object = new $className;
As an (exceptionally crude) example factory method:
public function &factory($className) {
require_once($className . '.php');
if(class_exists($className)) return new $className;
die('Cannot create new "' . $className . '" class - includes not found or class unavailable.');
}
have a look at example 3 from http://www.php.net/manual/en/language.oop5.basic.php
$className = 'Foo';
$instance = new $className(); // Foo()
Lets say ClassOne is defined as:
public class ClassOne
{
protected $arg1;
protected $arg2;
//Contructor
public function __construct($arg1, $arg2)
{
$this->arg1 = $arg1;
$this->arg2 = $arg2;
}
public function echoArgOne
{
echo $this->arg1;
}
}
Using PHP Reflection;
$str = "One";
$className = "Class".$str;
$class = new \ReflectionClass($className);
Create a new Instance:
$instance = $class->newInstanceArgs(["Banana", "Apple")]);
Call a method:
$instance->echoArgOne();
//prints "Banana"
Use a variable as a method:
$method = "echoArgOne";
$instance->$method();
//prints "Banana"
Using Reflection instead of just using the raw string to create an object gives you better control over your object and easier testability (PHPUnit relies heavily on Reflection)
// Way #1
$className = "App\MyClass";
$instance = new $className();
// Way #2
$className = "App\MyClass";
$class = new \ReflectionClass($className);
// Create a new Instance without arguments:
$instance = $class->newInstance();
// Create a new Instance with arguments (need a contructor):
$instance = $class->newInstanceArgs(["Banana", "Apple"]);
I want to use a variable (string value) to call a Class. Can I do it ? I search for PHP ReflectionClass but I do not know how to use a method from Reflection Result. Like this:
foreach($menuTypes as $key => $type){
if($key != 'Link'){
$class = new \ReflectionClass('\App\Models\\' . $key);
//Now $class is a ReflectionClass Object
//Example: $key now is "Product"
//I'm fail here and cannot call the method get() of
//the class Product
$data[strtolower($key) . '._items'] = $class->get();
}
}
Without ReflectionClass:
$instance = new $className();
With ReflectionClass: use the ReflectionClass::newInstance() method:
$instance = (new \ReflectionClass($className))->newInstance();
I found one like this
$str = "ClassName";
$class = $str;
$object = new $class();
You can use directly like below
$class = new $key();
$data[strtolower($key) . '._items'] = $class->get();
The risk is that the class doesn't exist. So it's better to check before instantiating.
With php's class_exists method
Php has a built-in method to check if the class exists.
$className = 'Foo';
if (!class_exists($className)) {
throw new Exception('Class does not exist');
}
$foo = new $className;
With try/catch with rethrow
A nice approach is trying and catching if it goes wrong.
$className = 'Foo';
try {
$foo = new $className;
}
catch (Exception $e) {
throw new MyClassNotFoundException($e);
}
$foo->bar();
Is it possible to store a reference to an object's property (class member variable which holds a scalar data such as string or integer) within an object of a different class?
I am trying to have the following two echo statements produce identical results.
<?php
$x = new Type;
$x->name = 'abcd';
echo "x.name=" . $x->name . '<br/>';
echo "x.obj.name=" . $x->obj->value . '<br/>';
class Type
{
public $obj; //Instance of Property (Property class defined below)
public $name;
function __construct()
{
$this->obj = new Property($this->name);
}
}
class Property
{
public $value;
function __construct($v)
{
$this->value = $v;
}
}
$this->obj = new Property($this->name);
Is called at the time of object creation. Which is executed before the assignment.
i.e.
When you call $x = new Type;
The constructor is called and you try to copy 'name' which is empty by then
May be what you want it following, rather than passing the value, pass $this and keep the referance.
<?php
class Type
{
public $obj; //Instance of Property (Property class defined below)
public $name;
function __construct()
{
$this->obj = new Property($this);
}
}
class Property
{
public $value;
function __construct($ref)
{
$this->value = $ref;
}
}
$x = new Type;
$x->name = 'abcd';
echo "x.name=" . $x->name . '<br/>';
echo "x.obj.name=" . $x->obj->value->name . '<br/>';
You can pass the name value inside the constructor.
$x = new Type('abcd');
Without doing that, your constructor will not know what $this->name is yet. So we use it in the constructor and set the classes property before using it.
function __construct($p_name){
$this->name = $p_name;
$this->obj = new Property($this->name);
}
You could just as easily set the value after calling the constructor and then initialize the reference afterwards -
class Type {
public $obj;
public $name;
function setProperty(){
$this->obj = new Property($this->name);
}
}
$x = new Type;
$x->name = 'abcd';
$x->setProperty();
echo "x.name=" . $x->name;
echo "x.obj.name=" . $x->obj->value;
This is an old question but just to add to this.
You can have an object with methods and properties inside of another object..
Example
$obj1 = new class1();
$obj2 = new class2($obj1); // you just grabbed $obj1 and stuck it inside $obj2
Now you can use the stored object's methods like so:
$obj2->obj1->method_from_obj1();
or access the stored object's properties like so:
$obj2->obj1->property_of_obj1;
This is SUPER convenient if you instantiated an object of some API and want to use the API methods inside of your own object.
While at the time of answering this question is 9+ years old, I've encountered a similar issue today and found a way to do what's requested.
In short: you should use references. Here's a a working example (PHP 8):
<?php
class Source
{
public int $counter = 10;
}
class Consumer
{
public int $value = 0;
public function __construct(int &$value)
{
$this->value = &$value;
}
}
$source = new Source();
// Pass property of Source instance to the consumer.
$consumer = new Consumer($source->counter);
assert($consumer->value === 10);
// Changing value in the Source instance.
$source->counter = 15;
// ... and value in the consumer updated as well.
assert($consumer->value === 15);
exit;
So, the answer is yes, it is possible.
I am trying to perform a backup/restore function for static properties of classes. I can get a list of all of the static properties and their values using the reflection objects getStaticProperties() method. This gets both private and public static properties and their values.
The problem is I do not seem to get the same result when trying to restore the properties with the reflection objects setStaticPropertyValue($key, $value) method. private and protected variables are not visible to this method as they are to getStaticProperties(). Seems inconsistent.
Is there any way to set a private/protected static property using reflection classes, or any other way for that matter?
TRIED
class Foo {
static public $test1 = 1;
static protected $test2 = 2;
public function test () {
echo self::$test1 . '<br>';
echo self::$test2 . '<br><br>';
}
public function change () {
self::$test1 = 3;
self::$test2 = 4;
}
}
$test = new foo();
$test->test();
// Backup
$test2 = new ReflectionObject($test);
$backup = $test2->getStaticProperties();
$test->change();
// Restore
foreach ($backup as $key => $value) {
$property = $test2->getProperty($key);
$property->setAccessible(true);
$test2->setStaticPropertyValue($key, $value);
}
$test->test();
For accessing private/protected properties of a class we may need to set the accessibility of that class first, using reflection. Try the following code:
$obj = new ClassName();
$refObject = new ReflectionObject( $obj );
$refProperty = $refObject->getProperty( 'property' );
$refProperty->setAccessible( true );
$refProperty->setValue(null, 'new value');
For accessing private/protected properties of a class, using reflection, without the need for a ReflectionObject instance:
For static properties:
<?php
$reflection = new \ReflectionProperty('ClassName', 'propertyName');
$reflection->setAccessible(true);
$reflection->setValue(null, 'new property value');
For non-static properties:
<?php
$instance = new SomeClassName();
$reflection = new \ReflectionProperty(get_class($instance), 'propertyName');
$reflection->setAccessible(true);
$reflection->setValue($instance, 'new property value');
You can implement also a class internal method to change the object properties access setting and then set value with $instanve->properyname = .....:
public function makeAllPropertiesPublic(): void
{
$refClass = new ReflectionClass(\get_class($this));
$props = $refClass->getProperties();
foreach ($props as $property) {
$property->setAccessible(true);
}
}
I have two classes, class ClassOne { } and class ClassTwo {}. I am getting a string which can be either "One" or "Two".
Instead of using a long switch statement such as:
switch ($str) {
case "One":
return new ClassOne();
case "Two":
return new ClassTwo();
}
Is there a way I can create an instance using a string, i.e. new Class("Class" . $str);?
Yes, you can!
$str = 'One';
$class = 'Class'.$str;
$object = new $class();
When using namespaces, supply the fully qualified name:
$class = '\Foo\Bar\MyClass';
$instance = new $class();
Other cool stuff you can do in php are:
Variable variables:
$personCount = 123;
$varname = 'personCount';
echo $$varname; // echo's 123
And variable functions & methods.
$func = 'my_function';
$func('param1'); // calls my_function('param1');
$method = 'doStuff';
$object = new MyClass();
$object->$method(); // calls the MyClass->doStuff() method.
You can simply use the following syntax to create a new class (this is handy if you're creating a factory):
$className = $whatever;
$object = new $className;
As an (exceptionally crude) example factory method:
public function &factory($className) {
require_once($className . '.php');
if(class_exists($className)) return new $className;
die('Cannot create new "' . $className . '" class - includes not found or class unavailable.');
}
have a look at example 3 from http://www.php.net/manual/en/language.oop5.basic.php
$className = 'Foo';
$instance = new $className(); // Foo()
Lets say ClassOne is defined as:
public class ClassOne
{
protected $arg1;
protected $arg2;
//Contructor
public function __construct($arg1, $arg2)
{
$this->arg1 = $arg1;
$this->arg2 = $arg2;
}
public function echoArgOne
{
echo $this->arg1;
}
}
Using PHP Reflection;
$str = "One";
$className = "Class".$str;
$class = new \ReflectionClass($className);
Create a new Instance:
$instance = $class->newInstanceArgs(["Banana", "Apple")]);
Call a method:
$instance->echoArgOne();
//prints "Banana"
Use a variable as a method:
$method = "echoArgOne";
$instance->$method();
//prints "Banana"
Using Reflection instead of just using the raw string to create an object gives you better control over your object and easier testability (PHPUnit relies heavily on Reflection)
// Way #1
$className = "App\MyClass";
$instance = new $className();
// Way #2
$className = "App\MyClass";
$class = new \ReflectionClass($className);
// Create a new Instance without arguments:
$instance = $class->newInstance();
// Create a new Instance with arguments (need a contructor):
$instance = $class->newInstanceArgs(["Banana", "Apple"]);