I've implemented an additional feature for type hints that will throw an exception instead of bailing out in case an incorrect type is passed.
Test script: <?php class Date { } class Article { public function setCreated_at(Date $date) { echo __CLASS__, '::', __FUNCTION__, ' called with '; var_export($date); echo "\n"; } public function setLastchange([Date] $date) { echo __CLASS__, '::', __FUNCTION__, ' called with '; var_export($date); echo "\n"; } } $a= new Article(); $a->setLastchange(new Date()); $a->setLastchange(NULL); // Passes $a->setCreated_at(new Date()); try { $a->setCreated_at(NULL); // Fails } catch (IllegalArgumentException $e) { echo "Caught: "; var_dump($e); } $a->setCreated_at(1); // Fails echo "Alive"; // Will not show up ?> Output: --------------------------------------------------------------------- [EMAIL PROTECTED]:~/devel/php > ./php5/sapi/cli/php hints.php article::setlastchange called with class date { } article::setlastchange called with NULL article::setcreated_at called with class date { } Caught: object(illegalargumentexception)#2 (3) { ["message"]=> string(38) "Argument 1 must be an instance of date" ["file"]=> string(36) "/usr/home/thekid/devel/php/hints.php" ["line"]=> int(4) } Fatal error: Uncaught exception! in Unknown on line 0 --------------------------------------------------------------------- A unified diff is attached. - Timm
Index: Zend/ZEND_CHANGES =================================================================== RCS file: /repository/ZendEngine2/ZEND_CHANGES,v retrieving revision 1.55 diff -u -r1.55 ZEND_CHANGES --- Zend/ZEND_CHANGES 7 Mar 2003 16:45:41 -0000 1.55 +++ Zend/ZEND_CHANGES 27 Mar 2003 16:11:06 -0000 @@ -177,6 +177,10 @@ function b(Bar $bar) { // ... } + + function c([Bar] $bar) { + // ... + } } $a = new FooBar; @@ -184,10 +188,14 @@ $a->a($b); $a->b($b); + $a->c($b); + $a->c(NULL); ?> These class type hints are not checked upon compilation, as would - be the case in a typed language, but during runtime. + be the case in a typed language, but during runtime. Type hints in + square brackets (as seen in function "c") denote passing of NULL is + also allowed. This means that @@ -202,6 +210,21 @@ die('Argument 1 must be an instance of ClassName'); } } + + and + + function foo([ClassName] $object) { + // ... + } + + is equivalent to + + function foo($object) { + if (!is_null($object) && !($object instanceof ClassName)) { + die('Argument 1 must be an instance of ClassName'); + } + } + . This syntax only applies to objects/classes, not built-in types. Index: Zend/zend_default_classes.c =================================================================== RCS file: /repository/ZendEngine2/zend_default_classes.c,v retrieving revision 1.3 diff -u -r1.3 zend_default_classes.c --- Zend/zend_default_classes.c 23 Mar 2003 17:18:31 -0000 1.3 +++ Zend/zend_default_classes.c 27 Mar 2003 16:11:07 -0000 @@ -22,6 +22,7 @@ #include "zend_API.h" zend_class_entry *default_exception_ptr; +zend_class_entry *illegalargument_exception_ptr; ZEND_FUNCTION(exception) { @@ -113,17 +114,23 @@ {NULL, NULL, NULL} }; -static void zend_register_default_exception(TSRMLS_D) +static void zend_register_default_exceptions(TSRMLS_D) { - zend_class_entry default_exception; + zend_class_entry default_exception, illegalargument_exception; INIT_CLASS_ENTRY(default_exception, "exception", default_exception_functions); default_exception_ptr = zend_register_internal_class(&default_exception TSRMLS_CC); + + INIT_CLASS_ENTRY(illegalargument_exception, "illegalargumentexception", NULL); + illegalargument_exception_ptr = zend_register_internal_class_ex( + &illegalargument_exception, + default_exception_ptr, + NULL TSRMLS_CC); } ZEND_API void zend_register_default_classes(TSRMLS_D) { - zend_register_default_exception(TSRMLS_C); + zend_register_default_exceptions(TSRMLS_C); } /* Index: Zend/zend_execute.c =================================================================== RCS file: /repository/ZendEngine2/zend_execute.c,v retrieving revision 1.448 diff -u -r1.448 zend_execute.c --- Zend/zend_execute.c 26 Mar 2003 20:42:23 -0000 1.448 +++ Zend/zend_execute.c 27 Mar 2003 16:11:08 -0000 @@ -4011,17 +4011,52 @@ { zval *arg = get_zval_ptr(&EX(opline)->op2, EX(Ts), &EG(free_op2), BP_VAR_R); zend_class_entry *ce = EX_T(EX(opline)->op1.u.var).EA.class_entry; + int allowed; + + switch (Z_TYPE_P(arg)) { + case IS_OBJECT: + allowed= instanceof_function(Z_OBJCE_P(arg), ce TSRMLS_CC); + break; + + case IS_NULL: + allowed= (EX(opline)->op1.op_type == IS_VAR); + break; + + default: + allowed= 0; + } - if ((Z_TYPE_P(arg) != IS_OBJECT) - || !instanceof_function(Z_OBJCE_P(arg), ce TSRMLS_CC)) { + if (!allowed) { char *error_msg; + zend_class_entry **exception_ce = NULL; + zval *exception; if (ce->ce_flags & ZEND_ACC_INTERFACE) { error_msg = "implement interface"; } else { error_msg = "be an instance of"; } - zend_error(E_ERROR, "Argument %d must %s %s", EX(opline)->extended_value, error_msg, ce->name); + + if (zend_lookup_class("illegalargumentexception", sizeof("illegalargumentexception")- 1, &exception_ce TSRMLS_CC) == FAILURE) { + zend_error(E_ERROR, "Argument %d must %s %s", EX(opline)->extended_value, error_msg, ce->name); + + /* Bails out */ + } else { + char* message; + + message = (char *) emalloc(1024); + snprintf(message, 1024, "Argument %d must %s %s", EX(opline)->extended_value, error_msg, ce->name); + + ALLOC_ZVAL(exception); + INIT_PZVAL(exception); + object_init_ex(exception, *exception_ce); + add_property_string_ex(exception, "message", sizeof("message"), message, 0); + add_property_string_ex(exception, "file", sizeof("file"), zend_get_executed_filename(TSRMLS_C), 0); + add_property_long_ex(exception, "line", sizeof("line"), zend_get_executed_lineno(TSRMLS_C)); + + EG(exception) = exception; + RETURN_FROM_EXECUTE_LOOP(execute_data); + } } NEXT_OPCODE(); Index: Zend/zend_language_parser.y =================================================================== RCS file: /repository/ZendEngine2/zend_language_parser.y,v retrieving revision 1.105 diff -u -r1.105 zend_language_parser.y --- Zend/zend_language_parser.y 26 Mar 2003 20:42:23 -0000 1.105 +++ Zend/zend_language_parser.y 27 Mar 2003 16:11:09 -0000 @@ -453,7 +453,8 @@ optional_class_type: /* empty */ { $$.op_type = IS_UNUSED; } - | fully_qualified_class_name { $$ = $1; } + | fully_qualified_class_name { $$ = $1; $$.op_type = IS_CONST; } + | '[' fully_qualified_class_name ']' { $$ = $2; $$.op_type = IS_VAR; } ; function_call_parameter_list:
-- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php