Skip to content

Instantly share code, notes, and snippets.

@paragonie-scott
Last active November 18, 2017 07:07
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save paragonie-scott/a6d1f3022079871e902a to your computer and use it in GitHub Desktop.
Save paragonie-scott/a6d1f3022079871e902a to your computer and use it in GitHub Desktop.
PHP7 Strict Typing or Else

Let's say you have a file like this:

<?php
declare(strict_types=1);

class Foo
{
    protected $x;
    public function __construct(array $x = [])
    {
        $this->x = $x;
    }
    
    public function bar(int $y): string
    {
        if (!array_key_exists($y, $this->z)) {
            throw new Exception("Key not found");
        }
    }
    
    public function baz(string $y): int
    {
        foreach ($this->x as $key => $value) {
            if ($y === $value) {
                return $key;
            }
        }
        throw new Exception("Value not found");
    }
}

PHP 7 enforces strictness on a per-file basis. So even though you're using them, if someone writes another script that calls it like this, it will work:

<?php
require "src/Foo.php";
$data = new Foo(['a', 'b', 'c', 'def']);
var_dump($data->bar('2')); // string(1) "c"

If you wanted to be completely hostile towards your users and demand they use strict types, here's how you do it:

<?php
declare(strict_types=1);

class Foo
{
    protected $x;
    public function __construct(array $x = [])
    {
        $this->x = $x;
    }
    
    // Notice: No parameter type declarations
    public function bar($y): string
    {
        return $this->actualBar($y);
    }
    // Notice: No parameter type declarations
    public function baz($y): int
    {
        return $this->actualBaz($y);
    }
    
    protected function actualBar(int $y): string
    {
        if (!array_key_exists($y, $this->z)) {
            throw new Exception("Key not found");
        }
    }
    
    protected function actualBaz(string $y): int
    {
        foreach ($this->x as $key => $value) {
            if ($y === $value) {
                return $key;
            }
        }
        throw new Exception("Value not found");
    }

Because the public API doesn't enforce types, PHP won't use weakly-typed conversion rules. It will pass them wholesale.

Then, when your public API methods (which exist in bat country a.k.a. strict_types=1 land) pass them to your protected methods, the strict types rules will be enforced. And thus, TypeError gets thrown, regardless of your user's type preference.

@jeremygiberson
Copy link

@narfbg Oh yeah, I totally overlooked that detail.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment