Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:439 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 48986 invoked from network); 28 Mar 2003 17:15:38 -0000 Received: from unknown (HELO moutng.kundenserver.de) (212.227.126.188) by pb1.pair.com with SMTP; 28 Mar 2003 17:15:38 -0000 Received: from [212.227.126.160] (helo=mrelayng.kundenserver.de) by moutng.kundenserver.de with esmtp (Exim 3.35 #1) id 18yxS4-0008Ne-00; Fri, 28 Mar 2003 18:15:36 +0100 Received: from [217.80.180.213] (helo=[217.80.180.213]) by mrelayng.kundenserver.de with asmtp (Exim 3.35 #1) id 18yxS4-0000l3-00; Fri, 28 Mar 2003 18:15:36 +0100 To: engine2@lists.zend.com Cc: internals@lists.php.net In-Reply-To: <1048781764.25691.593.camel@localhost> References: <1048781764.25691.593.camel@localhost> Content-Type: multipart/mixed; boundary="=-94exCCO0kI8AQb/7FVwo" Organization: Message-ID: <1048871727.25691.664.camel@localhost> Mime-Version: 1.0 X-Mailer: Ximian Evolution 1.2.1 Date: 28 Mar 2003 18:15:27 +0100 Subject: Re: [Zend Engine 2] Type hints revisited [IllegalArgumentException instead of E_ERROR] From: thekid@thekid.de (Timm Friebe) --=-94exCCO0kI8AQb/7FVwo Content-Type: text/plain Content-Transfer-Encoding: 7bit On Thu, 2003-03-27 at 17:16, Timm Friebe wrote: > 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. [...LONG disussion...] After reading through a bunch of mails this generated, I get the idea that most people here would be happier with an E_WARNING and the function not being executed. That gives: - the OOP purist the possibility to throw an exception (in a userland error handler) - the SOAP server a way to nicely recover - the API designer a way to tell the user (s)he's messed up - the "standard" programmer what (s)he's used to (PHP is quite forgiving in the way it handles incorrect argument types and usually warns about this) Attached is the E_WARNING variant, an example script and its output. - Timm --=-94exCCO0kI8AQb/7FVwo Content-Disposition: attachment; filename=zend_hints_warning.diff Content-Type: text/x-patch; name=zend_hints_warning.diff; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit 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 28 Mar 2003 17:09:53 -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_execute.c =================================================================== RCS file: /repository/ZendEngine2/zend_execute.c,v retrieving revision 1.449 diff -u -r1.449 zend_execute.c --- Zend/zend_execute.c 27 Mar 2003 17:57:47 -0000 1.449 +++ Zend/zend_execute.c 28 Mar 2003 17:09:54 -0000 @@ -4011,9 +4011,22 @@ { 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; if (ce->ce_flags & ZEND_ACC_INTERFACE) { @@ -4021,7 +4034,9 @@ } else { error_msg = "be an instance of"; } - zend_error(E_ERROR, "Argument %d must %s %s", EX(opline)->extended_value, error_msg, ce->name); + + zend_error(E_WARNING, "Argument %d must %s %s", EX(opline)->extended_value, error_msg, ce->name); + 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 28 Mar 2003 17:09:55 -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: --=-94exCCO0kI8AQb/7FVwo Content-Disposition: attachment; filename=hints.php Content-Type: application/x-php; name=hints.php Content-Transfer-Encoding: 7bit utime= $arg < 0 ? time() : $arg; } else { $this->utime= strtotime($arg); } } public function toString($fmt= 'r') { return date($fmt, $this->utime); } } class Revision { public $version = 0, $author = '', $date = NULL; public function __construct($version, $author, [Date] $date= NULL) { $this->version= $version; $this->author= $author; $this->date= $date ? $date : new Date(); } public function getDate() { return $this->date; } } class Article { public $created_at = NULL, $lastchange = NULL, $revisions = array(); public function setCreated_at(Date $date) { $this->created_at= $date; } public function addRevision(Revision $revision) { $this->revisions[]= $revision; return $revision; } public function setLastchange([Date] $date) { $this->lastchange= $date; } } $a= new Article(); $a->setLastchange(new Date()); $a->setLastchange(NULL); // Passes $a->setCreated_at(new Date()); $a->setCreated_at(NULL); // Fails var_dump($a); var_dump($a->addRevision(new Revision(1, 'timm'))->getDate()->toString()); // Pass 0 as value for date parameter $date= $a->addRevision(new Revision(2, 'foo', 0))->getDate(); var_dump($date); // Prints "NULL" ?> --=-94exCCO0kI8AQb/7FVwo Content-Disposition: attachment; filename=hints.php.out Content-Type: text/plain; name=hints.php.out; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Warning: Argument 1 must be an instance of date in /usr/home/thekid/devel/php/hints.php on line 42 object(article)#1 (3) { ["created_at"]=> object(date)#2 (1) { [""]=> int(1048871463) } ["lastchange"]=> NULL ["revisions"]=> array(0) { } } string(31) "Fri, 28 Mar 2003 18:11:03 +0100" Warning: Argument 3 must be an instance of date in /usr/home/thekid/devel/php/hints.php on line 25 NULL --=-94exCCO0kI8AQb/7FVwo--