So erstellen Sie neue Eigenschaften dynamisch

73

Wie kann ich eine Eigenschaft aus einem bestimmten Argument in der Methode eines Objekts erstellen?

class Foo{

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

  }

}

Und ich möchte in der Lage sein, auf die Immobilie zuzugreifen wie:

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

echo $object->hello;

Ist es auch möglich, dass ich das Eigentum öffentlich / geschützt / privat machen könnte? Ich weiß, dass es in diesem Fall öffentlich sein sollte, aber ich möchte vielleicht einige magische Methoden hinzufügen, um geschützte Eigenschaften und Sachen zu erhalten :)


Ich glaube, ich habe eine Lösung gefunden:

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

  }

Denkst du, es ist eine gute Idee?

Alex
quelle

Antworten:

106

Es gibt zwei Methoden, um dies zu tun.

Erstens können Sie Eigenschaften direkt dynamisch von außerhalb der Klasse erstellen:

class Foo{

}

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

Oder wenn Sie eine Eigenschaft mit Ihrer createPropertyMethode erstellen möchten :

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

$foo = new Foo();
$foo->createProperty('hello', 'something');
Mauris
quelle
Vielen Dank. Ich brauche es aber in der Klasse. Es ist etwas kompliziert zu erklären, die Eigenschaften sind tatsächlich Objekte, die Site-Erweiterungen sind, die der Site-Administrator aktivieren / deaktivieren kann :) Aber ich werde meine Lösung verwenden, ich denke, es ist besser, sie in einem Array zu behalten.
Alex
3
Ist es möglich, sie als privat oder geschützt festzulegen?
Marcio Mazzucato
3
Ich denke, die Sonne stimmt. Die Linie $this->$name = $value;sollte eigentlich sein$this->name = $value;
Victor D.
14
Oder $this->{$name} = $value;nein?
Victor
4
Wenn Sie einen dynamischen Eigenschaftsnamen wie in diesem Fall möchten, möchten wir das Attribut "Hallo". Wenn Sie " $this->{$name}Istead of $this->nameCause" verwenden, $this->namewird nur eine
Namenseigenschaft erstellt
10

Das folgende Beispiel ist für diejenigen gedacht, die keine ganze Klasse deklarieren möchten.

$test = (object) [];

$prop = 'hello';

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

echo $test->hello; // prints Hiiiiiiiiiiiiiiii
Crownlessking
quelle
einfache und voll dynamische Lösung, wie diese viel. Vielen Dank
Mili
8

Die Überladung von Immobilien ist sehr langsam. Wenn Sie können, versuchen Sie es zu vermeiden. Wichtig ist auch die Implementierung der beiden anderen magischen Methoden:

__isset (); __unset ();

Wenn Sie später bei der Verwendung dieser Objektattribute keine häufigen Fehler finden möchten

Hier sind einige Beispiele:

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

EDITIERT nach Alex Kommentar:

Sie können die Zeitunterschiede zwischen beiden Lösungen selbst überprüfen (ändern Sie $ 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
quelle
1
Ich bin süchtig nach __get / __set / __call. Ich verwende sie praktisch in jeder Klasse, um eine nette API zu erhalten, wenn ich diese Klasse verwende ... Ich brauchte __isset bisher nicht. Können Sie einen Link oder etwas mit einigen Benchmarks im Zusammenhang mit Überladung bereitstellen?
Alex
Entschuldigen Sie die schlechten Nachrichten, aber __call ist auch sehr langsam
Abraham Covelo
1
Zeigen Sie einige Verweise / Beweise auf "Eigenschaftsüberladung ist langsam".
Pacerier
1
@ Pacerier verwenden Sie den Benchmark-Code, den ich in meine Antwort eingegeben habe, und überprüfen Sie die Zeit, die für beide Lösungen auf Ihren eigenen Servern aufgewendet wurde
Abraham Covelo
6

Verwenden Sie die Syntax: $ object -> {$ property} wobei $ property eine Zeichenfolgenvariable ist und $ object dies sein kann, wenn es sich innerhalb der Klasse oder eines Instanzobjekts befindet

Live-Beispiel: 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;

Ergebnis: 50

Razan Paul
quelle
1
Dies ist die Antwort, nach der ich gesucht habe. Ich bin bereits neu, dass Sie nur auf Eigenschaften in Objekten verweisen können, die zuvor noch nicht deklariert wurden ... $ object-> example = "hello"; Ich habe mehr darüber nachgedacht, wie Sie die Eigenschaft dynamisch zum Objekt hinzufügen und gleichzeitig dynamisch angeben, wie Sie die Eigenschaft aufrufen möchten.
andmar8