PHP Arrays - Eine All-In-One Lösung

Tags:

Das PHP Array ist ein enorm mächtiges Konstrukt. Es ist - wie PHP auch - sehr flexibel gebaut und auf viele, unterschiedliche Arten verwendbar. Im Folgenden setze ich das Grundwissen voraus, wie Arrays in PHP angewandt werden. Sicherheitshalber noch einmal ein paar Fakten:

Oder in Code ausgedrückt:

// Array mit numerischen Indexen
$a = array('Eins', 'Zwei', 'Drei');

// Assoziatives Array
$a = array('Null' => 'Eins', 'Eins' => 'Zwei', 'Zwei' => 'Drei');

// Mixed Array
$a = array(4 => 'Eins', 'Fünf' => 'Zwei', 'Drei');

Der interne Zeiger wird bei jedem numerischen Key um eins hochgezählt. Im letztem Beispiel hat das Element Drei deshalb den Index 5.

In den meisten Programmiersprachen gibt es mehrere Konstrukte zur Haltung von Daten. Dies hat vor allem den Vorteil, dass die Daten klarer strukturiert und je nach Anwendung auf definierte Weise gehandhabt werden. Im Folgenden möchte ich auf ein paar dieser Konstrukte eingehen, sie auf einfache Art erklären und anschliessend zeigen, wie sie mittels SPL auch in PHP verwendet werden können.

Hashtable

Eine Hashtable, oder auch Hashmap, kann man sich als klassisches, assoziatives PHP Array vorstellen. Allerdings ohne besagte Limitierungen hinsichtlich Indexe. Die Definition ist ein bisschen wässerig, da es in PHP keine strenge Typisierung gibt. In vielen anderen Programmiersprachen ist ein Array immer von nur einem Typ (String-Array, Byte-Array, etc.).

class Hashtable implements ArrayAccess 
{
    protected $_data = array();

    public function offsetSet($key, $value)
    {
        $key = $this->_normalizeKey($key);
        $this->_data[$key] = $value;
    }

    public function offsetGet($key)
    {
        $key = $this->_normalizeKey($key);
        return $this->_data[$key];
    }

    public function offsetUnset($key)
    {
        $key = $this->_normalizeKey($key);
    unset($this->_data[$key]);
    }

    public function offsetExists($key)
    {
        $key = $this->_normalizeKey($key);
        return isset($this->_data[$key]);
    }

    protected function _normalizeKey($key)
    {
        if ($key instanceof stdClass) {
            $key = spl_object_hash($key);
        }
        elseif (is_array($key)) {
            $key = md5(serialize($key));
        }

        return $key;
    }
}

$h  = new Hashtable();
$o1 = new stdClass();
$o2 = new stdClass();
$h[$o1] = $o2;

In der sogenannten Standard PHP Library (SPL) gibt es eine Klasse zum Speichern von Objekten. Da diese fest in PHP integriert ist, hat sie klare Geschwindigkeitsvorteile gegenüber einer eigenen Lösung in PHP. Etienne Kneuss hat dazu in seinem Blog weitere, interessante Informationen.

$s  = new SplObjectStorage();
$o1 = new stdClass();
$o2 = new stdClass();

// Seit PHP 5.1
$s->attach($o1);
$s->detach($o1);

// Seit PHP 5.3
$s[$o1] = $o2;

Queue

Eine Queue iteriert im sogenannten FIFO-Modus (First In, First Out) über die Elemente. Dies bedeutet, dass die Elemente zuerst zurückgegeben werden, die auch zuerst hinzugefügt wurden. Dies entspring dem Standard-Iterierungsverfahren von Arrays in PHP (z.B. bei foreach()).

class Queue
{
    protected $_data = array();

    public function enqueue($value)
    {
        $this->_data[] = $value;
        return $this;
    }

    public function dequeue()
    {
        return array_shift($this->_data);
    }
}

$q = new Queue();
$q->enqueue('Eins')
  ->enqueue('Zwei')
  ->enqueue('Drei');

echo $q->dequeue(); // Eins
echo $q->dequeue(); // Zwei
echo $q->dequeue(); // Drei

Auch hier kann die SPL seit PHP 5.3 helfen:

$q = new SplQueue();
$q[] = 1;
$q[] = 2;
$q[] = 3;

// 1, 2, 3
foreach ($q as $e)  {
    echo $e;
}

Stack

Der Stack ist sowas wie das Gegenstück zu einer Queue. Er verwendet das LIFO-Verfahren (Last In, First Out), welches die Element zuerst zurückgibt, die zuletzt angehängt wurden.

class Stack
{
    protected $_data = array();

    public function push($value)
    {
        $this->_data[] = $value;
        return $this;
    }

    public function pop()
    {
        return array_pop($this->_data);
    }
}

$s = new Stack();
$s->push('Eins')
  ->push('Zwei')
  ->push('Drei');

echo $s->pop(); // Drei
echo $s->pop(); // Zwei
echo $s->pop(); // Eins

Und wieder kann uns die SPL helfen. Wiederum ist PHP 5.3 Kriterium.

$q = new SplStack();
$q[] = 1;
$q[] = 2;
$q[] = 3;

// 3, 2, 1
foreach ($q as $e)  {
    echo $e;
}

Dictionary

Den Dictionary kann man sich als assoziatives Array mit fest definierten Typen für Key und Value vorstellen. Hier eine sehr abstrakte Implementierung.

class Dictionary
{
    protected $_keyType   = null;
    protected $_valueType = null;
    protected $_data      = array();

    public function __construct($keyType, $valueType)
    {
        $this->_keyType   = $keyType;
        $this->_valueType = $valueType;
    }

    public function add($key, $value)
    {
        if (!$this->_assert($this->_keyType, $key)) {
            throw new Exception('Key must be of type "' . $this->_keyType . '"');
        }

        if (!$this->_assert($this->_valueType, $value)) {
            throw new Exception('Value must be of type "' . $this->_valueType . '"');
        }

        // Adding key/value pair
        // ...
    }

    protected function _assert($type, $value)
    {
        if (function_exists('is_' . $type)) {
            return call_user_func('is_' . $type, $value);
        }

        return $value instanceof $type;
    }
}

$d = new Dictionary('int', 'stdClass');
$d->add(1, new stdClass());   // Success
$d->add('1', new stdClass()); // Fail
$d->add(1, 'foobar');         // Fail

Hierzu gibt es leider keine Klasse in der SPL.

Weitere Datenstrukturen in der SPL

Die SPL kennt noch weitere Konstrukte zur Datenhaltung, wie SplHeap, SplPriorityQueue, etc. Hier möchte ich aber nur noch auf eine bestimmte Struktur eingehen: SplFixedArray.

Das SplFixedArray gibt es ebenfalls erst seit PHP 5.3 und unterscheidet sich in folgenden Punkten vom klassischen PHP Array:

Und so schaut es aus:

$a = new SplFixedArray(2);
$a[0] = 'Eins';
$a[1] = 'Zwei';

// Triggert eine RuntimeException, da die Grösse des Arrays überschritten wurde
$a[2] = 'Drei';

// Folgendes geht aber
$a->setSize(3);
$a[2] = 'Drei';

Ich empfehle als Lektüre die PHP Dokumentation zur SPL. Ausserdem findet ihr im Entwicklerblog von studiVZ eine interessante Benchmark betreffend SplQueue und SplStack, und im Blog von IDONTPLAYDARTS eine Benchmark zu SplFixedArray.

Haut rein, in die Tasten! :)

Ähnliche Artikel

Kommentare