Can we dynamically create and initialize an object in PHP?
This is the normal code:
class MyClass{
var $var1 = null;
var $var2 = null;
.
.
public function __construct($args){
foreach($args as $key => $value)
$this->$key = $value;
}
}
---------------------
$args = ($_SERVER['REQUEST_METHOD'] == "POST") ? $_POST : $_REQUEST;
$obj = new MyClass($args);
The above code works fine. Please note that the names of REQUEST parameters are accurately mapped with the members of class MyClass.
But can we do something like this:
$class = "MyClass";
$obj = new $class;
If we can do like this, then can we initialize $obj by using $args.
According to this post, $obj = $class should work. But it does not work for me. I tried get_class_vars($obj). It threw an exception.
Thanks
It's more a comment, but I leave it here more prominently:
$class = "MyClass";
$obj = new $class($args);
This does work. See newDocs.
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;
?>
You can use Reflection to instanciate an object with parameters.
<?php
class Foo {
protected $_foo;
protected $_bar;
public function __construct($foo, $bar)
{
$this->_foo = $foo;
$this->_bar = $bar;
}
public function run()
{
echo $this->_foo . ' ' . $this->_bar . PHP_EOL;
}
}
$objectClass = 'Foo';
$args = array('Hello', 'World');
$objectReflection = new ReflectionClass($objectClass);
$object = $objectReflection->newInstanceArgs($args);
$object->run();
See Reflection on php manual.
Related
I've got some problem.
I want to call static method of class from another class.
Class name and method are created dynamically.
It's not really hard to do like:
$class = 'className';
$method = 'method';
$data = $class::$method();
BUT, i want to to do it like this
class abc {
static public function action() {
//some code
}
}
class xyz {
protected $method = 'action';
protected $class = 'abc';
public function test(){
$data = $this->class::$this->method();
}
}
And it doesn't work if i don't assign $this->class to a $class variable, and $this->method to a $method variable.
What's the problem?
In PHP 7.0 you can use the code like this:
<?php
class abc {
static public function action() {
return "Hey";
}
}
class xyz {
protected $method = 'action';
protected $class = 'abc';
public function test(){
$data = $this->class::{$this->method}();
echo $data;
}
}
$xyz = new xyz();
$xyz->test();
For PHP 5.6 and lower you can use the call_user_func function:
<?php
class abc {
static public function action() {
return "Hey";
}
}
class xyz {
protected $method = 'action';
protected $class = 'abc';
public function test(){
$data = call_user_func([
$this->class,
$this->method
]);
echo $data;
}
}
$xyz = new xyz();
$xyz->test();
The object syntax $this->class, $this->method makes it ambiguous to the parser when combined with :: in a static call. I've tried every combination of variable functions/string interpolation such as {$this->class}::{$this->method}(), etc... with no success. So assigning to a local variable is the only way, or call like this:
$data = call_user_func(array($this->class, $this->method));
$data = call_user_func([$this->class, $this->method]);
$data = call_user_func("{$this->class}::{$this->method}");
If you need to pass arguments use call_user_func_array().
Is it possible to run php method on property change? Like shown in the example below:
Class:
class MyClass
{
public MyProperty;
function __onchange($this -> MyProperty)
{
echo "MyProperty changed to " . $this -> MyProperty;
}
}
Object:
$MyObject = new MyClass;
$MyObject -> MyProperty = 1;
Result:
"MyProperty changed to 1"
Like #lucas said, if you can set your property as private within the class, you can then use the __set() to detect a change.
class MyClass
{
private $MyProperty;
function __set($name, $value)
{
if(property_exists('MyClass', $name)){
echo "Property". $name . " modified";
}
}
}
$r = new MyClass;
$r->MyProperty = 1; //Property MyProperty changed.
You can achieve this best by using a setter method.
class MyClass
{
private MyProperty;
public function setMyProperty($value)
{
$this->MyProperty = $value;
echo "MyProperty changed to " . $this -> MyProperty;
}
}
Now you simply call the setter instead of setting the value yourself.
$MyObject = new MyClass;
$MyObject -> setMyProperty(1);
This post is quite old, but I have to deal with the same issue and a typical class with multiple fields. Why using private properties ?
Here is what I implemented :
class MyClass {
public $foo;
public $bar;
function __set($name, $value) {
if(!property_exists('MyClass', $name)){ // security
return;
}
if ('foo' == $name) { // test on the property needed to avoid firing
// "change event" on every private properties
echo "Property " . $name . " modified";
}
$this->$name = $value;
}
}
$r = new MyClass();
$r->bar = 12;
$r->foo = 1; //Property foo changed.
var_dump($r);
/*
object(MyClass)[1]
public 'foo' => int 1
public 'bar' => int 12
*/
Using the magic method __set:
class Foo {
protected $bar;
public function __set($name, $value) {
echo "$name changed to $value";
$this->$name = $value;
}
}
$f = new Foo;
$f->bar = 'baz';
It may be a better and more conventional idea to use a good old-fashioned setter instead:
class Foo {
protected $bar;
public function setBar($value) {
echo "bar changed to $value";
$this->bar = $value;
}
}
$f = new Foo;
$f->setBar('baz');
Consider following example:
<?php
class p{
public $name = 'jimmy';
public $sex = 'male';
private $age = 31;
// there should be more unknow properties here ..
function test(){
echo $this->name;
}
function get_p_as_json(){
// how can i get json of this class which contains only public properties ?
// {"name":"jimmy","sex":"male"}
}
}
$p = new p();
$json = $p->get_p_as_json();
echo $json;
Question: How to get all public properties of a class as JSON?
You just create another class q extends from p. And then the code looks like following:
class p {
public $name = 'jimmy';
public $sex = 'male';
private $age = 31;
// there should be more unknown properties here ..
function test(){
echo $this->name;
}
}
class q extends p {
function get_p_as_json($p) {
return json_encode(get_object_vars($p));
}
}
$q = new q();
$p = new p();
$json = $q->get_p_as_json($p);
echo $json;
$a = array();
$reflect = new ReflectionClass($this /* $foo */);
$props = $reflect->getProperties(ReflectionProperty::IS_PUBLIC);
foreach ($props as $prop) {
/* here you can filter for spec properties or you can do some recursion */
$a[ $prop->getName() ] = $a[ $prop->getValue()];
}
return json_encode($a);
Since the public members can also be accessed outside of the class..
Accessing members outside of the class
$p = new p();
foreach($p as $key => $value) {
$arr[$key]=$value;
}
Demo
Accessing the public members within the class by making use of ReflectionClass
<?php
class p{
public $name = 'jimmy';
public $sex = 'male';
private $age = 31;
// there should be more unknow properties here ..
function test(){
echo $this->name;
}
function get_p_as_json(){
static $arr;
$reflect = new ReflectionClass(p);
$props = $reflect->getProperties(ReflectionProperty::IS_PUBLIC);
foreach ($props as $prop) {
$arr[$prop->getName()]=$prop->getValue($this); //<--- Pass $this here
}
return json_encode($arr);
}
}
$p = new p();
echo $json=$p->get_p_as_json();
Demo
The best way to do this would not be to call a method of the class, per se.
However, you could initiate the following:
$myPublicMethodsInJson = json_encode(get_class_methods($p));
However, you would not be able to call get_class_methods from within the class because it will return ALL of your methods, private and public. When you call it from outside of the class it will only return the public methods.
i have something like this:
class foo
{
//code
}
$var = new foo();
$var->newVariable = 1; // create foo->newVariable
$var->otherVariable = "hello, im a variable"; //create foo->otherVariable
i can get in class foo a list of all variables defined outside by user (newVariable, otherVariable,etc)? Like this:
class foo
{
public function getUserDefined()
{
// code
}
}
$var = new foo();
$var->newVariable = 1; // create foo->newVariable
$var->otherVariable = "hello, im a variable"; //create foo->otherVariable
var_dump($var->getUserDefined()); // returns array ("newVariable","otherVariable");
Thanks!.
Yes, using get_object_vars() and get_class_vars():
class A {
var $hello = 'world';
}
$a = new A();
$a->another = 'variable';
echo var_dump(get_object_vars($a));
echo '<hr />';
// Then, you can strip off default properties using get_class_vars('A');
$b = get_object_vars($a);
$c = get_class_vars('A');
foreach ($b as $key => $value) {
if (!array_key_exists($key,$c)) echo $key . ' => ' . $value . '<br />';
}
What is your goal? Imo it's not very good practice (unless you really know what you are doing). Maybe it's good idea consider create some class property like "$parameters" and then create setter and getter for this and use it in this way:
class foo {
private $variables;
public function addVariable($key, $value) {
$this->variables[$key] = $value;
}
public function getVariable($key) {
return $this->variables[$key];
}
public function hasVariable($key) {
return isset($this->variables[$key]);
}
(...)
}
$var = new foo();
$var->addVariable('newVariable', 1);
$var->addVariable('otherVariable', "hello, im a variable");
And then you can use it whatever you want, for example get defined variable:
$var->getVariable('otherVariable');
To check if some var is already defined:
$var->hasVariable('someVariable')
get_class_vars() http://php.net/manual/en/function.get-class-vars.php
You question is not clear though.
$var->newVariable = 1;
there are two possible contex of above expression
1) you are accessing class public variables.
like
class foo
{
public $foo;
public function method()
{
//code
}
}
$obj_foo = new foo();
$obj_foo->foo = 'class variable';
OR
2) you are defining class variable runtime using _get and _set
class foo
{
public $foo;
public $array = array();
public function method()
{
//code
}
public function __get()
{
//some code
}
public function __set()
{
// some code
}
}
$obj_foo = new foo();
$obj_foo->bar= 'define class variable outside the class';
so in which context your question is talking about?
I have a variable $className which is name of declared class in php and I want
create an object of this class
lunch a static method of this class
$obj = new $className();
$var = $className::method();
1:
$obj = new $className
2:
$className::someMethod($parameter)
There's also the Reflection API. E.g.:
<?php
$rc = new ReflectionClass('A');
// question 1) create an instance of A
$someArgs = array(1,2,3);
$obj = $rc->newInstanceArgs($someArgs);
// question 2) invoke static method of class A
$rm = $rc->getMethod('foo');
if ( !$rm->isStatic() ) {
echo 'not a static method';
}
else {
$rm->invokeArgs(null, $someArgs);
}
class A {
public function __construct($a, $b, $c) { echo "__construct($a,$b,$c)\n";}
public static function foo($a, $b, $c) { echo "foo($a,$b,$c)\n";}
}