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