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.
It's a bad solution because internals ultimately decided against the good one (enforceable type checks). I was very vocal back then and I still believe 2 separate syntaxes was the way to go, but it's too late now.