Don't return associative arrays!
Tags: php, oop, beginners
Published: 2018-08-15 10:30:08

---
title: Don't return associative arrays!
published: true
description: Demand clear answers from your objects, don't accept mumbling 
tags: php, OOP, beginners
---
I hate dealing with associative arrays when i'm writing client code. The
problem with arrays is that there is no context. There is no special knowledge. They are usually just data packaged in an inconvenient format. The worst part is that they tie me to a particular implementation.

Now, i don't mean that you shouldn't return arrays that have uniform data. Returning an array of certain type of objects is fine(ish). Although you still cannot promise through your API that it will contain only certain type of data.

Arrays may work as an internal representation of data for some class, but that is the way it should stay - internal.

What i'm talking about is those nasty multidimensional arrays with hardcoded strings as keys.

Consider this:

```php
class AcmeFileSender implements FileSender
{
    public function sendFiles(FileCollection $files): array
    {
        $sent = 0;
        $errors = [];
        foreach ($files as $file) {
            try {
                $this->send($file);
                $sent++;
            } catch (SenderException $exception) {
                $errors[] = $exception->getMessage();
            }
        }
        return [
            "sent" => $sent,
            "failed" => count($errors),
            "errors" => $errors
        ];
    }

    public function send(File $file): void {//...}
}
```

Doesn't look that bad right? It's just three keyed values in an associative array.

The problem in this case is, that the array cannot promise us anything about it's structure. This means that when we write our client code we are dependent of `sendFiles()`'s implementation. We have to know exactly what the keys are and what sort of data is behind those keys.

In OOP we should not be concerned about implementation details of other classes. We care only about the interfaces.

Lately i've been bumping in to something that might be an even more serious offense:

```php
public function processStuff($stuff): array
{
    //...
    return [$someArray, $someObject];
}

//... in client code
list($someArray, $someObject) = $this->processor->processStuff($stuff);
```

Now, it's one thing to return this kind of abominations from private methods. But when you start designing your public API like this all hope is lost. This is pretty much a dead give away that you are dealing with a procedural code base. In procedural code bases everything is data and can (and will) be manipulated.

In the case above the issue is the lack of context. What does it mean when you receive `someArray` and `someObject` together? Why are they returned together? It's clear that the implementation of `processStuff()` knows about how it is used. So it's not really designed as much as glued together with some client code. The client code is very tightly coupled to implementation of `processStuff()`.

In many cases there's some confusion about how to define responsibilities. Code does something and returns some indication of it's success to the client. There is not much trust between the client and the server. The client is paranoid about server's quality of work.

What can we do to make the first example better? Value objects. `sendFiles()` would be a lot more expressive by using value objects.

```php
interface SenderReport
{
    public function sent(): int;
    public function failures(): int;
    public function errors(): Iterator;
    public function print(): string;
}
```

We will update FileSender and it's implementations.

```php
class AcmeFileSender implements FileSender
{
    //...
    public function sendFiles(FileCollection $files): SenderReport
    {
        //...
        return new FileSenderReport($sent, count($errors), $errors);
    }
}
```

Now we can rely on the interface of `SenderReport` instead of being painfully aware of the implementation of `FileSender::sendFiles()`. Now we have context. Also, we can change the implementations of `FileSender` freely.

--

Don't return associative arrays from the public API. Evaluate if you really even have to return a value. And, if you must, return something that has an interface that you and users of your code can rely on.