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?

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');

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

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

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


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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.