Objekt in Array umwandeln – wird eine magische Methode aufgerufen?

Lesezeit: 7 Minuten

Ich habe ein Objekt der Klasse Foo:

class Foo extends Bar {
    protected $a;
    protected $b;
}

$obj = new Foo();

Was ich tun möchte (und muss), ist dieses Objekt in ein Array umzuwandeln, wie folgt:

$arr = (array)$obj;

Gibt es eine magische (oder nicht magische :)) Methode, die gerade aufgerufen wird? Oder gibt es eine andere Möglichkeit, es abzufangen? Ich weiß, dass ich eine einfache Methode schreiben kann, z. asArray() in Foo, aber ich suche nach mehr “nativen” PHP-Möglichkeiten.

Nein

Es gibt kein __toArray magische Methode in PHP. Ein Verbesserungsvorschlag wurde abgelehnt in 2006 mit folgender Antwort:

[2006-08-20 11:12 UTC] [email protected]

Warum nicht einfach eine Methode asArray() haben, vielleicht sogar als Teil einer Schnittstelle:

Schnittstelle ArrayConversion {Funktion asArray(); }

Sehen Sie, wir haben __toString, da es in Sprachkonstrukten wie echo, print und anderen internen Funktionen unterstützt wird. Aber wir haben uns bereits gegen eine Autokonvertierung für Arrays entschieden. Daher wird es in keinem Sprachkonstrukt unterstützt. Das heißt, es wird nichts dafür benötigt und nichts, was Sie gegen die obige Schnittstelle gewinnen würden. Tatsächlich würden Sie es php komplexer machen, weil Sie nur eine weitere magische Funktion hinzufügen würden.

Es ist daher sehr unwahrscheinlich, dass es in einer zukünftigen Version implementiert wird (was schade ist, wenn Sie mich fragen).

  • Aber hey, haben wir nicht wenigstens das goto-Konstrukt bekommen? zittert

    – Tacon

    27. Dezember 2013 um 13:16 Uhr

  • Es ist seltsam, dass er das sagt, denn PHP hat tatsächlich eine Objekt-zu-Array-Konvertierung: php.net/manual/en/…

    – Stirb jetzt

    21. Januar 2014 um 15:03 Uhr

  • Die Frage bezieht sich eigentlich darauf, benutzerdefinierte Casting-Logik implementieren zu können.

    – Tacon

    21. Januar 2014 um 16:55 Uhr

  • Nur eine Anmerkung: 2019 diskutiert PHP jetzt __toArray() : wiki.php.net/rfc/to-array

    – Daniel Marschall

    29. November 2020 um 23:51 Uhr

Sie können die Klasse implementieren lassen ArrayAccess Schnittstelle. Dadurch können Sie das Objekt ohne Umwandlung wie ein Array behandeln und erhalten die vollständige Kontrolle darüber, wie die Mitglieder verwendet werden.

  • Obwohl nett, geht diese Antwort nicht wirklich auf die Frage ein. Sie sollten zumindest das Wort “nein” irgendwo einfügen 🙂

    – Hubro

    29. April 2013 um 8:39 Uhr

  • Guter Punkt, aber geben Sie irgendwo am Anfang der Antwort an, dass die Implementierung der ArrayAccess Die Schnittstelle reicht nicht aus, um ein Objekt in ein Array umzuwandeln.

    – Daniel Orlando

    22. Dezember 2015 um 0:38 Uhr


  • Es sollte auch beachtet werden, dass sich das Objekt erstreckt, um Elemente zu durchlaufen, die in dem Objekt enthalten sind ArrayAccess verwenden foreachmüssen Sie ebenfalls implementieren \IteratorAggregate oder \Iterator. Im Allgemeinen diejenigen, die die Array-Funktionalität innerhalb eines Objekts reproduzieren möchten implements \Countable, \IteratorAggregate, \ArrayAccess Sehen \ArrayObject.

    – Wird B.

    22. Januar 2016 um 15:31 Uhr


Leider nein, das Casting in ein Array löst keine magische Methode aus, wie es mit:

$s = (string)$obj;

was auslöst __toString() -Methode, die Sie überschreiben können.

Sie können jedoch eine benutzerdefinierte schreiben toArray() Methode.

Das könnte Sie auch interessieren Serializable Schnittstelle, mit der Sie eine benutzerdefinierte Serialisierungsstrategie schreiben können.

Nicht sicher, ob diese Frage noch relevant ist, aber PHP hat eingebaut ArrayObject Klasse, die es ermöglicht, ein Objekt als Array zu behandeln, und kann praktisch sein, wenn es als Container für Datenbankeinträge oder -sammlungen verwendet wird.

Dies ist möglicherweise keine bewährte Methode in Bezug auf strikte Typen, ermöglicht jedoch die Behandlung von Objekten als Array, und beide Anweisungen sind gültig.

$obj = new ArrayObject(['a' => 'alpha']);
var_dump($obj['a']); //alpha
var_dump($obj->getOffset('a'));//alpha

Allerdings müssen Sie das Verhalten von im Auge behalten ArrayObject

$obj = new ArrayObject(['a' => 'alpha']);
//Access Property
var_dump($obj['a']); //alpha
var_dump($obj->offsetGet('a'));//alpha
var_dump($obj->a); //null Notice: Undefined property: ArrayObject::$a

//Serialization
var_dump(serialize($obj));// string 'C:11:"ArrayObject":41:{x:i:0;a:1:{s:1:"a";s:5:"alpha";};m:a:0:{}}' (length=65)
var_dump($obj->serialize());// string 'x:i:0;a:1:{s:1:"a";s:5:"alpha";};m:a:0:{}'
var_dump(serialize($obj) === $obj->serialize());// false !!!

//Setting Properties
$obj['b'] = 'beta'; //OK
$obj->c="gamma"; //value becomes object property!!!
var_dump($obj);
/* OBJECT DUMP
object(ArrayObject)[13]
  public 'c' => string 'gamma' (length=5)
  private 'storage' =>
    array (size=2)
      'a' => string 'alpha' (length=5)
      'b' => string 'beta' (length=4)
 */

//Property validation as array
var_dump(isset($obj['a']));//true
var_dump(isset($obj['b']));//true
var_dump(isset($obj['c']));//false
//Property validation as object
var_dump(isset($obj->a));//false
var_dump(isset($obj->b));//false
var_dump(isset($obj->c));//true

//Typecasting
var_dump((array)$obj);
/*
array (size=2)
  'a' => string 'alpha' (length=5)
  'b' => string 'beta' (length=4)
 */

//var_dump((string)$obj);// Catchable fatal error: Object of class ArrayObject could not be converted to string

ArrayObject akzeptiert zwei Flags ArrayObject::STD_PROP_LIST als Standard und ArrayObject::ARRAY_AS_PROPS als Alternative.

Dies würde das Verhalten beim Lesen von Werten ändern, unterstützt jedoch nicht das Festlegen neuer Eigenschaften auf diese Weise. Hier ist ein Beispiel:

$obj = new ArrayObject(['a' => 'alpha'], ArrayObject::ARRAY_AS_PROPS);
//Access Property
var_dump($obj['a']); //alpha
var_dump($obj->offsetGet('a'));//alpha
var_dump($obj->a);//alpha

//Serialization
var_dump(serialize($obj));// string 'C:11:"ArrayObject":41:{x:i:0;a:1:{s:1:"a";s:5:"alpha";};m:a:0:{}}' (length=65)
var_dump($obj->serialize());// string 'x:i:0;a:1:{s:1:"a";s:5:"alpha";};m:a:0:{}'
var_dump(serialize($obj) === $obj->serialize());// false !!!

//Setting Properties
$obj['b'] = 'beta'; //OK
$obj->c="gamma"; //OK
var_dump($obj);
/* OBJECT DUMP
object(ArrayObject)[14]
  private 'storage' =>
    array (size=3)
      'a' => string 'alpha' (length=5)
      'b' => string 'beta' (length=4)
      'c' => string 'gamma' (length=5)
 */

//Property validation as array
var_dump(isset($obj['a']));//true
var_dump(isset($obj['b']));//true
var_dump(isset($obj['c']));//false !!!
//Property validation as object
var_dump(isset($obj->a));//true
var_dump(isset($obj->b));//true
var_dump(isset($obj->c));//true

//Typecasting
var_dump((array)$obj);
/*
array (size=2)
  'a' => string 'alpha' (length=5)
  'b' => string 'beta' (length=4)
 */

Um dieses Verhalten konsistenter zu machen, müssten Sie diese Klasse erweitern und magische Methoden implementieren __get(), __set(), __isset() und __unset().

Ein weiterer kniffliger Teil ist die Serialisierung, die Standardmethode serialize würde Ihnen eine Kopie mit Seriennummer zurücksenden $storage Variable anstelle des Objekts selbst, als Problemumgehung, um eine serialisierte Kopie der Instanz zurückzugeben, in der Sie die Standardserialisierung implementieren können __toString Methode, auf diese Weise verhält es sich richtig.

class FooObject extends ArrayObject
{
    public function __get($index)
    {
        if ($this->offsetExists($index)) {
            return $this->offsetGet($index);
        } else {
            throw new UnexpectedValueException('Undefined key ' . $index);
        }
    }

    public function __set($index, $value)
    {
        $this->offsetSet($index, $value);
        return $this;
    }

    public function __isset($index)
    {
        return $this->offsetExists($index);
    }

    public function __unset($index)
    {
        return $this->offsetUnset($index);
    }

    public function __toString()
    {
        return serialize($this);
    }
}

Anwendungsbeispiel

$obj2 = new FooObject(['a' => 'alpha']);
//Access Property
var_dump($obj2['a']); //alpha
var_dump($obj2->offsetGet('a'));//alpha
var_dump($obj2->a); //alpha

//Serialization
var_dump(serialize($obj));// string 'C:11:"ArrayObject":41:{x:i:0;a:1:{s:1:"a";s:5:"alpha";};m:a:0:{}}' (length=65)
var_dump($obj->serialize());// string 'x:i:0;a:1:{s:1:"a";s:5:"alpha";};m:a:0:{}'
var_dump(serialize($obj) === $obj->serialize());// false !!!

//Setting Properties
$obj2['b'] = 'beta'; //OK
$obj2->c="gamma"; //OK
var_dump($obj2);
/* OBJECT DUMP
object(FooObject)[14]
  private 'storage' (ArrayObject) =>
    array (size=3)
      'a' => string 'alpha' (length=5)
      'b' => string 'beta' (length=4)
      'c' => string 'gamma' (length=5)
 */

//Property validation as array
var_dump(isset($obj2['a']));//true
var_dump(isset($obj2['b']));//true
var_dump(isset($obj2['c']));//true
//Property validation as object
var_dump(isset($obj2->a));//true
var_dump(isset($obj2->b));//true
var_dump(isset($obj2->c));//true

//Typecasting
var_dump((array)$obj2);
/*
array (size=3)
  'a' => string 'alpha' (length=5)
  'b' => string 'beta' (length=4)
  'c' => string 'gamma' (length=5)
 */

Eine Möglichkeit, dies zu tun, ohne die ursprüngliche Klassendefinition zu ändern, ist die Verwendung von Reflektion. Dadurch können Sie die Eigenschaften der Klasse zur Laufzeit untersuchen.

Aus dem Handbuch entnommen: http://www.php.net/manual/en/reflectionclass.getproperties.php

<?php
class Foo {
    public    $foo  = 1;
    protected $bar  = 2;
    private   $baz  = 3;
}

$foo = new Foo();

$reflect = new ReflectionClass($foo);
$props   = $reflect->getProperties(ReflectionProperty::IS_PUBLIC | ReflectionProperty::IS_PROTECTED);

foreach ($props as $prop) {
    print $prop->getName() . "\n";
}

var_dump($props);

?>

The above example will output something similar to:
foo
bar
array(2) {
  [0]=>
  object(ReflectionProperty)#3 (2) {
    ["name"]=>
    string(3) "foo"
    ["class"]=>
    string(3) "Foo"
  }
  [1]=>
  object(ReflectionProperty)#4 (2) {
    ["name"]=>
    string(3) "bar"
    ["class"]=>
    string(3) "Foo"
  }
}

Benutzer-Avatar
Aghanim

Sie können get_object_vars($yourObject) verwenden, das ein assoziatives Array aller Eigenschaftsnamen/-werte zurückgibt, auf die aus dem Kontext zugegriffen werden kann.

Sehen http://php.net/manual/en/function.get-object-vars.php

Wenn Sie auf geschützte oder private Eigenschaften zugreifen möchten, wäre mein Rat, ArrayObject zu erweitern, das die Methode getArrayCopy() implementiert.

1282980cookie-checkObjekt in Array umwandeln – wird eine magische Methode aufgerufen?

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

Privacy policy