Created
May 12, 2015 09:39
-
-
Save aziraphale/914083c8ea483bc19248 to your computer and use it in GitHub Desktop.
Curious hack to allow scalar type hinting in PHP 5.2+
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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