Set-Eigenschaften in PHP erhalten

Lesezeit: 9 Minuten

Ich komme aus dem C#-Umfeld und fange an, PHP in der Schule zu lernen. Ich bin es gewohnt, meine Eigenschaften in C# so festzulegen.

public int ID { get; set; }

Was ist das Äquivalent dazu in PHP?

Vielen Dank.

Benutzer-Avatar
Mchl

Es gibt keine, obwohl es welche gibt einige Vorschläge zur Umsetzung das in zukünftigen Versionen. Vorerst müssen Sie leider alle Getter und Setter von Hand deklarieren.

private $ID;

public function setID($ID) {
  $this->ID = $ID;
}

public function getID() {
  return $this->ID;
}

Für etwas Magie (PHP mag Magie) können Sie nachschlagen __set und __get Magische Methoden.

Beispiel

class MyClass {

  private $ID;

  private function setID($ID) {
    $this->ID = $ID;
  }

  private function getID() {
    return $this->ID;
  }


  public function __set($name,$value) {
    switch($name) { //this is kind of silly example, bt shows the idea
      case 'ID': 
        return $this->setID($value);
    }
  }

  public function __get($name) {
    switch($name) {
      case 'ID': 
        return $this->getID();
    }
  }

}


$object = new MyClass();
$object->ID = 'foo'; //setID('foo') will be called

Danke für eure Antworten an alle. Es hat mir geholfen, so etwas zu erstellen:

In meiner Elternklasse:

public function __get($name){

    if (ObjectHelper::existsMethod($this,$name)){
        return $this->$name();
    }

    return null;
}

public function __set($name, $value){

    if (ObjectHelper::existsMethod($this,$name))
        $this->$name($value);
}

ObjectHelper::existsMethod ist eine Methode, die nur prüft, ob die angegebene geschützte Methode existiert.

private $_propertyName = null;

protected function PropertyName($value = ""){

    if (empty($value)) // getter
    {
        if ($this-> _propertyName != null)
            return $this->_propertyName;
    }
    else // setter
    {
        $this-> _propertyName = $value;
    }

    return null;
}

So kann ich so etwas in jeder Klasse verwenden:

$class = new Class();
$class->PropertyName = "test";
echo $class->PropertyName;

Ich wurde von C# inspiriert 🙂

Was haltet ihr davon, Jungs?

Hier ist mein ObjectHelper, falls ihn jemand verwenden möchte:

namespace Helpers;

use ReflectionMethod;

class ObjectHelper {

public static function existsMethod($obj, $methodName){

    $methods = self::getMethods($obj);

    $neededObject = array_filter(
        $methods,
        function ($e) use($methodName) {
            return $e->Name == $methodName;
         }
    );

    if (is_array($neededObject))
        return true;

    return false;
}

public static function getMethods($obj){

    $var = new \ReflectionClass($obj);

    return $var->getMethods(ReflectionMethod::IS_PROTECTED);
}
}

  • Ich möchte so etwas verwenden, um die mühsame Boilerplate der Verwendung von PHP get/set zu reduzieren. Kann ich einige Verbesserungen an Ihrem Ansatz vorschlagen? 1) Fügen Sie den Methoden eine Benennungskonventionsanforderung der Präfixe „getPropertyName“ und „setPropertyName“ hinzu, um zu vermeiden, dass Aufrufer ALLE Methoden als Eigenschaften aufrufen können, was zu Verwirrung führt (oder fügen Sie eine konstante Liste von Eigenschaften hinzu).

    – Scipilot

    3. September 2018 um 16:37 Uhr

  • 2) Es wäre viel einfacher, eine Eigenschaft als eine übergeordnete Klasse zu verwenden (wahrscheinlich nicht verfügbar, als Sie dies geschrieben haben).

    – Scipilot

    3. September 2018 um 16:37 Uhr

  • 3) Erweitern Sie den Helfer weiter, um die eigentliche Get/Set-Boilerplate über eine Namenskonvention für Eigenschaften und einen dynamischen $propertyName auszuführen. Das wäre für mich der wertvollste Teil. Ich habe mich wegen der Menge an zusätzlichem Wiederholungscode für jede Eigenschaft nie mit PHPs get/set beschäftigt.

    – Scipilot

    3. September 2018 um 16:40 Uhr

  • 4) Ziehen Sie die leere Überprüfung für den “Get”-Fall fest. Wie von anderen angemerkt, möchten Sie die Eigenschaft auf leere Werte setzen, sicherlich 0 und “” und []. Null scheint am besten zu sein, obwohl es immer noch ausschließt, die Eigenschaft tatsächlich auf null zu setzen. Ich sehe keinen einfachen Weg, um diesen Geldautomaten zu umgehen, außer einer anderen Methode, oder die Getset-Einzelfunktion nicht auszuführen.

    – Scipilot

    3. September 2018 um 16:44 Uhr

  • Und wenn das alles steht, kann ein Performance-Benchmark nicht schaden! Wenn man bedenkt, dass das Festlegen einer Eigenschaft eine Aktivität auf so niedriger Ebene ist, kann die Leistung für einige Objekte oder ihre Verwendung kritisch sein. Vielleicht ist ein hartcodierter (oder generierter) Boilerplate doch viel effizienter.

    – Scipilot

    3. September 2018 um 16:50 Uhr

Benutzer-Avatar
Jaspreet Chahal

Mchi hat Recht, aber es gibt einen anderen Weg, dies zu tun, indem eine einzelne Funktion verwendet wird

    private $ID;

public function ID( $value = "" )

{

    if( empty( $value ) )

        return $this->ID;

    else

        $this->ID = $value;

}

Aber ja, dieser Ansatz entspricht ziemlich genau dem, was Sie in c# tun. aber das ist nur eine Alternative

Oder versuchen Sie es mit __set und __ von php in Ihrer Klasse. Weitere Informationen finden Sie hier

http://php.net/manual/en/language.oop5.overloading.php

  • Obwohl ein interessanter Ansatz, sehe ich einige Nachteile: Erstens impliziert der Name der Funktion nicht, was sie tut (kein Verb darin), zweitens, was wäre, wenn ich speziell einen leeren Wert auf ID setzen wollte? $class->ID(4); $class->ID(''); echo $class->ID(); würde 4 drucken …

    – Dan Seife

    16. Februar 2012 um 23:01 Uhr


  • @kassy. Deshalb sagte ich, es ist eine Alternative. In c# haben Sie kein setX oder getX als solches, obwohl Sie sie haben können, also dachte ich, ich zeige besser etwas, das ein bisschen mit c# übereinstimmen kann 🙂 das Beispiel, das Sie aufgelistet haben, um einen Nachteil des obigen Ansatzes hervorzuheben. Ich bin da bei Ihnen, aber es gibt eine Menge Dinge, die Sie tun können, um es so zu gestalten, wie Sie es möchten. Meine Idee war also nur, einen Ansatz aufzuzeigen, keine Lösung.

    – Jaspreet Chahal

    16. Februar 2012 um 23:07 Uhr


  • Entschuldige den Nekro. Dies kann jetzt jedoch mit dem variadic … Operator von PHP effektiver durchgeführt werden. function foo(...$args) { if (empty($args)) { return $this->foo; } else { $this->foo = $args[0]; } }

    – Erzählen

    25. April 2020 um 6:37 Uhr

Ein weiteres Beispiel mit dem Namen der Variablenfunktion

class MyClass {

  private $ID;
  protected $ID2;

  private function setID($ID) {
    $this->ID = $ID;
  }
  private function getID() {
    return $this->ID;
  }
  private function setID2($ID2) {
    $this->ID2 = $ID2;
  }

  private function getID2() {
    return $this->ID2;
  }
  public function __set($name,$value) {
    $functionname="set".$name;
    return $this->$functionname($value);
  }
  public function __get($name) {
    $functionname="get".$name;
    return $this->$functionname();
  }

}


$object = new MyClass();
$object->ID = 'foo'; //setID('foo') will be called
$object->ID2 = 'bar'; //setID2('bar') will be called

private $ID;

public function getsetID($value = NULL)
{
    if ($value === NULL) {
        return $this->ID;
    } else {
        $this->ID = $value;
    }
}

  • Wie setze ich die ID auf null?

    – Maxim Colesnik

    9. Februar 2018 um 15:25 Uhr


  • @MaximColesnic, if (func_num_args() === 0) kann dafür verwendet werden.

    – vp_arth

    12. Juni 2019 um 7:04 Uhr

Benutzer-Avatar
rmblstrp

Ich weiß, dass ich in dieser Frage etwas spät zur Party komme, aber ich hatte selbst die gleiche Frage / den gleichen Gedanken. Als C#-Entwickler, der PHP macht, möchte ich, wenn es der Job erfordert, eine einfache Möglichkeit haben, Eigenschaften zu erstellen, so wie ich es in C# tun könnte.

Ich habe heute Nachmittag einen ersten Entwurf erstellt, mit dem Sie die Hintergrundfelder erstellen und ihre Accessoren angeben oder reine Accessoren ohne Hintergrundfeld haben können. Ich werde meine Antwort aktualisieren, wenn sich der Code weiterentwickelt, und einen Link bereitstellen, wenn ich ihn in den Zustand versetze, in dem er als Composer-Paket importiert werden kann.

Der Einfachheit halber habe ich die Funktionalität als PHP-Eigenschaft erstellt, damit Sie sie in jede gewünschte Klasse einfügen können, anstatt eine Basisklasse erweitern zu müssen. Letztendlich hoffe ich, diese Funktionalität erweitern zu können, um zwischen externen öffentlichen Aufrufen an die Eigenschaften und geschützten/privaten Aufrufen zu unterscheiden.

Hier ist der Code für die Eigenschaft selbst:

trait PropertyAccessorTrait
{
    private static $__propertyAccessors = [];

    /* @property string $__propertyPrefix */

    public function __get($name)
    {
        $this->__populatePropertyAcessors($name);

        return $this->__performGet($name);
    }

    public function __set($name, $value)
    {
        $this->__populatePropertyAcessors($name);

        $this->__performSet($name, $value);
    }

    public function __isset($name)
    {
        // TODO: Implement __isset() method.
    }

    public function __unset($name)
    {
        // TODO: Implement __unset() method.
    }

    protected function __getBackingFieldName($name)
    {
        if (property_exists(self::class, '__propertyPrefix')) {
            $prefix = $this->__propertyPrefix;
        } else {
            $prefix = '';
        }

        return $prefix . $name;
    }

    protected function __canget($name)
    {
        $accessors = $this->__getPropertyAccessors($name);

        return $accessors !== null && isset($accessors['get']);
    }

    protected function __canset($name)
    {
        $accessors = $this->__getPropertyAccessors($name);

        return $accessors !== null && isset($accessors['set']);
    }

    protected function __performGet($name)
    {
        if (!$this->__canget($name)) {
            throw new \Exception('Getter not allowed for property: ' . $name);
        }

        $accessors = $this->__getPropertyAccessors($name)['get'];

        /* @var \ReflectionMethod $method */
        $method = $accessors['method'];

        if (!empty($method)) {
            return $method->invoke($this);
        }

        return $this->{$this->__getBackingFieldName($name)};
    }

    protected function __performSet($name, $value)
    {
        if (!$this->__canset($name)) {
            throw new \Exception('Setter not allowed for property: ' . $name);
        }

        $accessors = $this->__getPropertyAccessors($name)['set'];

        /* @var \ReflectionMethod $method */
        $method = $accessors['method'];

        if (!empty($method)) {
            return $method->invoke($this, $value);
        }

        $this->{$this->__getBackingFieldName($name)} = $value;
    }

    protected function __getPropertyAccessors($name)
    {
        return isset(self::$__propertyAccessors[$name])
            ? self::$__propertyAccessors[$name]
            : null
            ;
    }

    protected function __getAccessorsFromDocBlock($docblock)
    {
        $accessors = [];

        if (!empty(trim($docblock))) {
            $doclines = null;

            if (!empty($docblock)) {
                $doclines = explode("\n", $docblock);
            }

            if (!empty($doclines)) {
                foreach ($doclines as $line) {
                    if (preg_match('/@(get|set)\\s+(public|private|protected)/', $line, $matches)) {
                        $accessors[$matches[1]]['visibility'] = $matches[2];
                    }
                }
            }
        }

        return $accessors;
    }

    protected function __populatePropertyAcessors($name)
    {
        if ($this->__getPropertyAccessors($name) !== null) return;

        try {
            $property = new \ReflectionProperty(self::class, $this->__getBackingFieldName($name));
        } catch (\ReflectionException $ex) {
            $property = null;
        }

        $accessors = [];

        if ($property != null) {
            $accessors = $this->__getAccessorsFromDocBlock($property->getDocComment());
        }

        try {
            $methodName="get" . ucfirst($name);
            $method = new \ReflectionMethod(self::class, $methodName);
            $method->setAccessible(true);
            $accessors = array_merge($accessors, $this->__getAccessorsFromDocBlock($method->getDocComment()));
        } catch (\ReflectionException $ex) {
            $method = null;
        }


        if ($method !== null || isset($accessors['get'])) {
            $accessors['get']['method'] = $method;
        }

        try {
            $methodName="set" . ucfirst($name);
            $method = new \ReflectionMethod(self::class, $methodName);
            $method->setAccessible(true);
            $accessors = array_merge($accessors, $this->__getAccessorsFromDocBlock($method->getDocComment()));
        } catch (\ReflectionException $ex) {
            $method = null;
        }

        if ($method !== null || isset($accessors['set'])) {
            $accessors['set']['method'] = $method;
        }

        self::$__propertyAccessors[$name] = $accessors;
    }
}

Hier ist ein schneller Komponententest, den ich mit dem Codeception-Format erstellt habe:

<?php

class PropertyAssesorTraitTestClass
{
    use PropertyAccessorTrait;

    private $__propertyPrefix = '_';

    /**
     * @get public
     * @set public
     */
    private $_integer = 1;

    /**
     * @get public
     */
    private $_getonly = 100;

    /**
     * @set public
     */
    private $_setonly;

    private $_customDoubler;

    private function getCustomDoubler()
    {
        return $this->_customDoubler * 2;
    }

    private function setCustomDoubler($value)
    {
        $this->_customDoubler = $value * 2;
    }

    public $publicField = 1234;

    /**
     * @return int
     * @get public
     */
    private function getPureAccessor()
    {
        return $this->publicField;
    }

    /**
     * @param $value
     * @set public
     */
    private function setPureAccessor($value)
    {
        $this->publicField = $value;
    }

    private $_purePrivate = 256;
}

$I = new UnitTester($scenario);
$I->wantTo('Ensure properties are accessed correctly');

$instance = new PropertyAssesorTraitTestClass();
$I->assertSame(1, $instance->integer);

$instance->integer = 2;
$I->assertSame(2, $instance->integer);

$instance->integer = $instance->integer + 1;
$I->assertSame(3, $instance->integer);

$instance->integer++;
$I->assertSame(4, $instance->integer);

$I->assertSame(100, $instance->getonly);
$I->expectException('Exception', function () use ($instance) { $instance->getonly = 50; });

$instance->setonly = 50;
$I->expectException('Exception', function () use ($instance) { $a = $instance->setonly; });

$instance->customDoubler = 100;
$I->assertSame(400, $instance->customDoubler);

$I->assertSame(1234, $instance->publicField);
$instance->pureAccessor = 1000;
$I->assertSame(1000, $instance->publicField);
$instance->publicField = 1234;
$I->assertSame(1234, $instance->publicField);
$I->assertSame(1234, $instance->pureAccessor);

$I->expectException('Exception', function () use ($instance) { return $instance->purePrivate; });

  • Wie setze ich die ID auf null?

    – Maxim Colesnik

    9. Februar 2018 um 15:25 Uhr


  • @MaximColesnic, if (func_num_args() === 0) kann dafür verwendet werden.

    – vp_arth

    12. Juni 2019 um 7:04 Uhr

Benutzer-Avatar
vagustolga

das ist PHP; Sie müssen sich nicht festlegen

class MyClass {
  public $ID;
}

$object = new MyClass();
$object->ID = 'foo';
echo $object->ID;

wird funktionieren

1144690cookie-checkSet-Eigenschaften in PHP erhalten

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy