Skip to content

Instantly share code, notes, and snippets.

@aziraphale
Created May 12, 2015 09:39
Show Gist options
  • Save aziraphale/914083c8ea483bc19248 to your computer and use it in GitHub Desktop.
Save aziraphale/914083c8ea483bc19248 to your computer and use it in GitHub Desktop.
Curious hack to allow scalar type hinting in PHP 5.2+
<?php
// Definining these four classes is actually optional; the code functions fine
// without them, but IDEs obviously bitch about undefined classes.
// All have final-private constructors to prevent them ever being instantiated
// (or we could pass *actual objects* of these types to our type-hinted
// functions, where we'd have code that expected a string suddenly finding
// itself dealing with an object!
class string { final private function __construct(){} }
class boolean { final private function __construct(){} }
class double { final private function __construct(){} }
class integer { final private function __construct(){} }
// A function defined with type hints for "classes" with names that make them
// look like scalar types. PHP will trigger an error when we pass a *real*
// string to a function expecting an object of type "string", but we can
// handle that error ourselves and ignore it!
function myTest(string $foo, boolean $bar, double $baz, integer $qux)
{
echo "Hello, world.\r\n";
}
// Handle PHP's errors ourselves so that we can filter out the "expected" ones
set_error_handler(
function ($errno, $errstr, $errfile, $errline, array $errcontext) {
// Passing a scalar string to a function that we've type-hinted with a
// fictional class named "stringn" will result in an
// E_RECOVERABLE_ERROR with a string of:
// Argument 1 passed to myTest() must be an instance
// of string, string given, called in [...] on line 38
// and defined
if (
$errno === E_RECOVERABLE_ERROR &&
preg_match(
'/Argument \d+ passed to .+? must be an instance of '.
'(string|boolean|integer|double), \1 given, called in/iS',
$errstr
)) {
// This is an 'error' triggered by passing, e.g., a string to a
// method where PHP expects an object of type "string".
// So jump out of the error handler and prevent any more error
// handlers running
return true;
}
// A "real" error - return false so that any additional error-handling
// runs (including PHP's standard handler)
return false;
}
);
// Called with the expected arguments, the script functions as normal
myTest("foo", true, 1.23, 123);
// Called with incorrect arguments, PHP displays errors as expected
myTest(["foo"], 1, "1.23", 1.23);
// As demonstrated above, no type massaging of any kind is done. If you don't
// pass the exact type to the method, it will error out on you!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment