0

I have some data represented as multi-dimensional arrays. I would like to embed these data into my OO application and provide extra functionality to these data but also a way to access it both with the traditional random access and using an iterator (so I could use foreach). In other words I would like to implement a wrapping class for a multi-dimensional array.

What I already tried:

I. ArrayAccess The problem with this one is that the server uses PHP 5.2.17 and &offsetGet() gives an error, thus I can't return by reference, which means I can't implement multidimensional element access:

$obj[$key1][$key2] = $value;

Note, that upgrading to a newer PHP version is currently not an option

II. Using magic methods This is a bit trickier, but my problems rose when I tried using a variable as key. E.g.

$obj->$key1[$key2] = $value;

The interpreter first evaluated $key1[$key2] throwing a notice and returning the first char of $key1, and uses that as key on my array. I don't know how to solve this one either. I thought of using brackets to force operation priority, but that had the same problem as in my next attempt:

III. Using simple get and set functions Again, old PHP. It cries when I try to write:

$obj->get($key1)[$key2] = $value;

Because it doesn't know how to index an expression ending in round brackets.

There's still the lost resort option: make the array public and forget OO all together. But before I go there I want to be certain that there's just really no other way of doing this.

2 Answers 2

2

Sometimes, it's best shown with an example. For instance, you could have a multidimensional array with ordered quantities of a product, where the first index defines a customer, the second an order and the third the products. The value then is the quantity.

IV. Using simple get and set functions, but with multiple parameters:

$value = $obj->get($key1, $key2);
$obj->set($key1, $key2, $value);

or

$quantity = $orderedQuantities($customerName, $orderNo, $productCode);

The essence of writing an object wrapper, is that it looks like an object and behaves like such. If you implement it so that it looks and behaves like an array, you may just as well use an array. The only reason to wrap an array in an object that behaves like an array is that you can pass it around by reference, without using & parameters.

If that is your goal, just assign the array to $obj, and use $obj->arrayprop[$key1][$key2]. If on the other hand you want it to behave like an object, skip the array syntax altogether.

V. Using nested objects So using the same example, you can write a customers object (kind of a collection), which embeds order objects, etc..

$quantity = $customers->getCustomerByName($customerName)->getOrder($orderNo)->getProduct($productCode)->quantity;

or, to make it more readable:

$customer = $customers->getCustomerByName($customerName); $order = $customer->getOrder($orderNo); $orderLine= $order->getOrderLine($productCode); $quantity = $product->quantity;

Now, each of these entities are represented by an object. The advantage is that you can easily extend this structure with extra properties. You can give the customer collection 'findByCustomerNo' and 'findByName' methods to find a specific customer, but also a 'filterByPostalCode', which could return a new collection containing only the customers from that postal code.

$order could now contain functions to calculate totals.

$orderLine may contain only a productCode (key) and a quantity, but by making it an object, you can easily add discount, a customized name or description or other properties.

All in all, this structure allows a lot of flexibility, although it needs a little more typing at first and a little getting used to.

Sign up to request clarification or add additional context in comments.

3 Comments

My first thought was to implement an object that looks and behaves like an array with added array-like functionality. but turns out, that you can't implement something that looks like an array in PHP 5.2.17. So I tried staying with the "behaves like and a bit looks like" part, at least. But turns out, you can't really do that either. Thanks for your answer, I think I'll stick with the most straightforward $obj->arrayprop[$key1][$key2] way to do it, which I find really ugly, but... whatever. I already hate PHP way too much to care.
That's the spirit (I so actually agree). :) But to maybe change your mind, I've added V. Using nested objects.
This nested object thing actually works great. Not just as you described, but also in a generic way. Using nested objects solves the problem of passing by reference in I. so ArrayAccess is usable again. I post my code as answer. Thanks for pointing me into the right direction: to stop programming everything in a generic way. I think I'll throw out my code and rethink this, concentrating a bit more to the problem at hand against all the possible ways of using it in the future.
0

Using nested objects can make ArrayAccess work, without passing references. But you can forget about built in array functions completely.

<?php
class ArrObj implements ArrayAccess {
    private $arr;

    public function __construct($arr = null) {
        $this->arr = $arr;
    }

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

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

    public function offsetSet($key, $val) {
        return $this->arr[$key] = $val;
    }

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

$a = new ArrObj(array(
    'foo' => new ArrObj(array(
        'bar' => 'qwe'
    ))
));

echo $a['foo']['bar'] . '<br />';
$a['foo']['bar'] = 'asd';
echo $a['foo']['bar'] . '<br />';
?>

Outputs:

qwe
asd

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.