97

How can I create a property from a given argument inside a object's method?

class Foo{

  public function createProperty($var_name, $val){
    // here how can I create a property named "$var_name"
    // that takes $val as value?

  }

}

And I want to be able to access the property like:

$object = new Foo();
$object->createProperty('hello', 'Hiiiiiiiiiiiiiiii');

echo $object->hello;

Also is it possible that I could make the property public/protected/private ? I know that in this case it should be public, but I may want to add some magik methods to get protected properties and stuff :)


I think I found a solution:
  protected $user_properties = array();

  public function createProperty($var_name, $val){
    $this->user_properties[$var_name] = $val;

  }

  public function __get($name){
    if(isset($this->user_properties[$name])
      return $this->user_properties[$name];

  }

do you think it's a good idea?

Alex
  • 66,732
  • 177
  • 439
  • 641

4 Answers4

130

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');
mauris
  • 42,982
  • 15
  • 99
  • 131
  • thank you. I need it inside the class though. It's kind of complicated to explain, the properties are actually objects which are site extensions that the site administrator can enable/disable :) But I will use my solution, I think it's better to keep them inside an array. – Alex Jan 03 '12 at 02:33
  • 4
    Is it possible to set them as private or protectd? – Marcio Mazzucato Apr 26 '14 at 03:31
  • Setting property like this does not allow us to make it private or protected because it is set from public. However, you can try to work with OOP magic methods `__get()` and `__set()`. See http://stackoverflow.com/questions/4713680/php-get-and-set-magic-methods – mauris Apr 26 '14 at 05:17
  • Your second method of dynamic property creation will result in `Notice: Undefined variable: name ` Please check it – sun Jul 26 '14 at 10:40
  • 3
    I think sun is right on this one. The line `$this->$name = $value;` should actually be `$this->name = $value;` – Victor D. Aug 14 '14 at 14:06
  • 18
    Or `$this->{$name} = $value;`, no? – Victor Apr 24 '15 at 12:41
  • 4
    If you want a dynamic property name like in this case we want the hello attribute then use ``$this->{$name}`` istead of ``$this->name`` cause ``$this->name`` will only create a name property – ismnoiet Aug 21 '15 at 00:57
  • The first solution is deprecated in [PHP 8.2](https://www.php.net/manual/en/migration82.deprecated.php) `class Foo{} $foo = new Foo(); $foo->hello = 'Something';` – Malus Jan Aug 29 '23 at 19:54
25

The following example is for those who do not want to declare an entire class.

$test = (object) [];

$prop = 'hello';

$test->{$prop} = 'Hiiiiiiiiiiiiiiii';

echo $test->hello; // prints Hiiiiiiiiiiiiiiii
crownlessking
  • 1,182
  • 1
  • 17
  • 22
7

Property overloading is very slow. If you can, try to avoid it. Also important is to implement the other two magic methods:

__isset(); __unset();

If you don't want to find some common mistakes later on when using these object "attributes"

Here are some examples:

http://www.php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.members

EDITED after Alex comment:

You can check yourself the differences in time between both solutions (change $REPEAT_PLEASE)

<?php

 $REPEAT_PLEASE=500000;

class a {}

$time = time();

$a = new a();
for($i=0;$i<$REPEAT_PLEASE;$i++)
{
$a->data = 'hi';
$a->data = 'bye'.$a->data;
}

echo '"NORMAL" TIME: '.(time()-$time)."\n";

class b
{
        function __set($name,$value)
        {
                $this->d[$name] = $value;
        }

        function __get($name)
        {
                return $this->d[$name];
        }
}

$time=time();

$a = new b();
for($i=0;$i<$REPEAT_PLEASE;$i++)
{
$a->data = 'hi';
//echo $a->data;
$a->data = 'bye'.$a->data;
}

echo "TIME OVERLOADING: ".(time()-$time)."\n";
Abraham Covelo
  • 895
  • 7
  • 7
  • 1
    I'm kind of addicted to __get / __set / __call. I practically use them in every class to get nice API when using that class ... Didn't need __isset so far.. Can you provide a link or something with some benchmarks related to overloading? – Alex Jan 03 '12 at 02:38
  • Sorry for the bad news but __call is really slow too – Abraham Covelo Jan 03 '12 at 03:19
  • 1
    Show some references/evidence to "property overloading is slow". – Pacerier Oct 07 '14 at 17:06
  • 1
    @Pacerier use the benchmark code I put in my answer and check the time spent for both solutions in your own servers – Abraham Covelo Apr 10 '15 at 16:03
6

Use the syntax: $object->{$property} where $property is a string variable and $object can be this if it is inside the class or any instance object

Live example: http://sandbox.onlinephpfunctions.com/code/108f0ca2bef5cf4af8225d6a6ff11dfd0741757f

 class Test{
    public function createProperty($propertyName, $propertyValue){
        $this->{$propertyName} = $propertyValue;
    }
}

$test = new Test();
$test->createProperty('property1', '50');
echo $test->property1;

Result: 50

Razan Paul
  • 13,618
  • 3
  • 69
  • 61
  • 1
    This is the answer I was looking for, I already new that you can just reference properties in objects that haven't previously been declared... $object->example = "hello"; I was more after how do you dynamically add the property to object whilst also dynamically specifying what you want to call the property. – andmar8 Jun 26 '15 at 15:17