2

What would be the best way to check the type of an array in PHP?

Lets say I have the following:

class Toggler
{

    protected $devices;

    public function __construct(array $devices)
    {
        $this->devices = $devices;
    }

    public function toggleAll()
    {
        foreach ($this->devices as $device)
        {
            $device->toggle();
        }
    }

}

What happens here is simple: The Toggler class requires an array of 'Devices', loops over those devices and calls the toggle() method on them.

What I want however, is that the array of devices must contain only objects that implement the Toggleable interface (which would tell the object to supply a toggle() method).

Now I can't do something like this, right?

class Toggler
{

    protected $devices;

    public function __construct(Toggleable $devices)
    {
        $this->devices = $devices;
    }

    public function toggleAll()
    {
        foreach ($this->devices as $device)
        {
            $device->toggle();
        }
    }

}

As far as I know you can't typehint an array as an array in PHP has no type (unlike languages like C++).

Would you instead have to check type in the loop for each device? And throw an exception? What would be the best thing to do?

class Toggler
{

    protected $devices;

    public function __construct(array $devices)
    {
        $this->devices = $devices;
    }

    public function toggleAll()
    {
        foreach ($this->devices as $device)
        {
            if (! $device instanceof Toggleable) {
                throw new \Exception(get_class($device) . ' is not does implement the Toggleable interface.');
            }

            $device->toggle();
        }
    }

}

Is there a better, cleaner, way to do this? I figured as I was writing this pseudo code you would also need to check if the device is an object at all (else you can't do get_class($device)).

Any help would be appreciated.

Melvin Koopmans
  • 2,994
  • 2
  • 25
  • 33
  • http://stackoverflow.com/a/34273821/1848929 – hakki Apr 13 '17 at 18:29
  • It looks like you already found the solution. As an improvement I would do the `instanceof` validation when `$this->devices` is set (i.e. in the constructor) with two benefits: find any erroneous usage of class `Toggler` as soon as possible and make sure any object of the `Toggler` class is valid. Additional, a minor performance improvement: the constructor is called only once, another method may be called many times. – axiac Apr 13 '17 at 18:31
  • @hakiko Am I correct to say that `toggleAll()` would call a `toggle(Toggler $toggler)` for each item in the array? I love over-complicating problems lmao – Melvin Koopmans Apr 13 '17 at 18:33

1 Answers1

5

One option (requires PHP >= 5.6.0) is to define the method as

public function __construct(Toggleable ...$devices)

but you'll have to use array packing/unpacking on both sides; the constructor and wherever you instantiate the object, e.g.

$toggleAbles = [new Toggleable(), new Toggleable()];
$toggler = new Toggler(...$toggleAbles);
Mark Baker
  • 209,507
  • 32
  • 346
  • 385
  • Damn that is smart, seems like the shortest and most elegant way of solving the issue. Do you think it's a better solution to the problem than: http://stackoverflow.com/questions/34273367/type-hinting-in-php-7-array-of-objects/34273821#34273821 ? What if later someone forgets to unpack the array of devices and inserts the entire array instead, would that be a problem? – Melvin Koopmans Apr 13 '17 at 18:39
  • If somebody forgot to unpack the array before instantiating the Toggler, then you'd get an array passed to the constructor which would be invalid as per the `Toggleable` typehint, and you'd get a recoverable fatal error or a TypeError Exception (depending on the version of PHP) – Mark Baker Apr 13 '17 at 18:42
  • packed arguments must also be the last arguments in the function/constructor definition, which is another limitation – Mark Baker Apr 13 '17 at 18:43
  • ah exactly! Thanks for the clarification – Melvin Koopmans Apr 13 '17 at 19:22
  • Would you agree with me that it would be a nice to have that you can strictly set the type of an array in PHP? That way, like in languages such as C++, you can only have values of a certain datatype in an array. That way you could just typehint the abstract directly, instead of unpacking an array using the splat operator. – Melvin Koopmans Apr 13 '17 at 20:53
  • I'd agree; but I'm also aware that it has ben implemented for PHP with an RFC, and rejected because of the performance overhead of checking every element in the array... it may be put forward again someday, but unlikely in the near future – Mark Baker Apr 13 '17 at 21:28
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/141680/discussion-between-melvin-koopmans-and-mark-baker). – Melvin Koopmans Apr 13 '17 at 21:30