atom feed63 messages in net.php.lists.internals[PHP-DEV] Callable typehint
FromSent OnAttachments
Hannes MagnussonJun 6, 2011 12:41 pm.txt
Stas MalyshevJun 6, 2011 1:35 pm 
Hannes MagnussonJun 6, 2011 1:48 pm 
Christopher JonesJun 6, 2011 1:49 pm 
Stas MalyshevJun 6, 2011 2:16 pm 
Matthew Weier O'PhinneyJun 6, 2011 3:15 pm 
Pierre JoyeJun 6, 2011 3:26 pm 
Matthew Weier O'PhinneyJun 6, 2011 3:32 pm 
Etienne KneussJun 6, 2011 3:41 pm 
Chris StocktonJun 6, 2011 3:51 pm 
Chris StocktonJun 6, 2011 3:52 pm 
Ferenc KovacsJun 6, 2011 4:01 pm 
Stas MalyshevJun 6, 2011 4:01 pm 
Chris StocktonJun 6, 2011 4:20 pm 
Derick RethansJun 6, 2011 4:30 pm 
Martin ScottaJun 6, 2011 7:50 pm 
Jordi BoggianoJun 7, 2011 3:08 am 
Hannes MagnussonJun 7, 2011 6:59 am 
Richard QuadlingJun 7, 2011 7:03 am 
Hannes MagnussonJun 7, 2011 7:21 am 
Jaroslav HanslikJun 7, 2011 8:22 am 
Matthew Weier O'PhinneyJun 7, 2011 9:10 am 
Stas MalyshevJun 7, 2011 11:50 am 
David ZülkeJun 7, 2011 12:03 pm 
Stas MalyshevJun 7, 2011 12:12 pm 
David ZülkeJun 7, 2011 12:28 pm 
Anthony FerraraJun 7, 2011 12:37 pm 
Martin ScottaJun 7, 2011 1:28 pm 
Stas MalyshevJun 7, 2011 1:31 pm 
David ZülkeJun 7, 2011 1:32 pm 
Pierre JoyeJun 7, 2011 1:36 pm 
Mike van RielJun 7, 2011 1:43 pm 
Matthew Weier O'PhinneyJun 7, 2011 1:44 pm 
dukeofgamingJun 7, 2011 2:15 pm 
Matthew Weier O'PhinneyJun 7, 2011 2:41 pm 
dukeofgamingJun 7, 2011 3:38 pm 
Johannes SchlüterJun 7, 2011 4:39 pm 
David ZülkeJun 7, 2011 5:04 pm 
Alexey SheinJun 7, 2011 10:24 pm 
Hannes MagnussonJun 8, 2011 1:31 am 
Hannes MagnussonJun 8, 2011 1:38 am 
Alexey SheinJun 8, 2011 1:47 am 
Johannes SchlüterJun 8, 2011 3:04 am 
Hannes MagnussonJun 8, 2011 3:17 am 
Richard QuadlingJun 8, 2011 3:27 am 
Johannes SchlüterJun 8, 2011 3:28 am 
Hannes MagnussonJun 8, 2011 3:30 am 
Johannes SchlüterJun 8, 2011 3:31 am 
Richard QuadlingJun 8, 2011 3:31 am 
Anthony FerraraJun 8, 2011 6:31 am 
Martin ScottaJun 8, 2011 7:42 am 
Martin ScottaJun 8, 2011 7:48 am 
David ZülkeJun 8, 2011 8:53 am 
Johannes SchlüterJul 10, 2011 12:02 pm 
Stas MalyshevJul 10, 2011 12:57 pm 
Hannes MagnussonJul 11, 2011 1:21 am 
Stas MalyshevJul 11, 2011 1:27 am 
Peter CowburnJul 11, 2011 1:37 am 
Hannes MagnussonJul 11, 2011 1:38 am 
Stas MalyshevJul 11, 2011 1:43 am 
Ferenc KovacsMay 27, 2013 10:59 pm 
Peter CowburnMay 27, 2013 11:47 pm 
Ferenc KovacsMay 28, 2013 1:21 am 
Subject:[PHP-DEV] Callable typehint
From:Hannes Magnusson (hann@gmail.com)
Date:Jun 6, 2011 12:41:00 pm
List:net.php.lists.internals
Attachments:

Hi

As quickly mentioned in the '$arr = array('Hello', 'world'); $arr();' thread[1], we are hitting the need for a callable typehint.

See attached patch+phpt; Any objections to include it in 5.4?

-Hannes

[1] http://php.markmail.org/message/gdas65h3im52sleg

Index: Zend/zend.h =================================================================== --- Zend/zend.h (revision 311867) +++ Zend/zend.h (working copy) @@ -573,6 +573,7 @@ #define IS_RESOURCE 7 #define IS_CONSTANT 8 #define IS_CONSTANT_ARRAY 9 +#define IS_CALLABLE 10

/* Ugly hack to support constants as static array indices */ #define IS_CONSTANT_TYPE_MASK 0x00f Index: Zend/zend_execute.c =================================================================== --- Zend/zend_execute.c (revision 311867) +++ Zend/zend_execute.c (working copy) @@ -626,13 +626,24 @@ need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name,
&ce TSRMLS_CC); return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg,
class_name, zend_zval_type_name(arg), "" TSRMLS_CC); } - } else if (cur_arg_info->type_hint && cur_arg_info->type_hint == IS_ARRAY) { - if (!arg) { - return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the
type array", "", "none", "" TSRMLS_CC); - } + } else if (cur_arg_info->type_hint) { + switch(cur_arg_info->type_hint) { + case IS_ARRAY: + if (!arg) { + return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the
type array", "", "none", "" TSRMLS_CC); + }

- if (Z_TYPE_P(arg) != IS_ARRAY && (Z_TYPE_P(arg) != IS_NULL ||
!cur_arg_info->allow_null)) { - return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the
type array", "", zend_zval_type_name(arg), "" TSRMLS_CC); + if (Z_TYPE_P(arg) != IS_ARRAY && (Z_TYPE_P(arg) != IS_NULL ||
!cur_arg_info->allow_null)) { + return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the
type array", "", zend_zval_type_name(arg), "" TSRMLS_CC); + } + break; + case IS_CALLABLE: + if (!zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL) && (Z_TYPE_P(arg)
!= IS_NULL || !cur_arg_info->allow_null)) { + return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be
callable", "", zend_zval_type_name(arg), "" TSRMLS_CC); + } + break; + default: + zend_error(E_ERROR, "Unknown typehint"); } } return 1; Index: Zend/zend_language_scanner.l =================================================================== --- Zend/zend_language_scanner.l (revision 311867) +++ Zend/zend_language_scanner.l (working copy) @@ -1310,6 +1310,10 @@ return T_ARRAY; }

+<ST_IN_SCRIPTING>"callable" { + return T_CALLABLE; +} + <ST_IN_SCRIPTING>"++" { return T_INC; } Index: Zend/zend_compile.c =================================================================== --- Zend/zend_compile.c (revision 311867) +++ Zend/zend_compile.c (working copy) @@ -1849,28 +1849,40 @@ cur_arg_info->allow_null = 0;

if (class_type->u.constant.type != IS_NULL) { - cur_arg_info->type_hint = IS_OBJECT; - if (ZEND_FETCH_CLASS_DEFAULT ==
zend_get_class_fetch_type(Z_STRVAL(class_type->u.constant),
Z_STRLEN(class_type->u.constant))) { - zend_resolve_class_name(class_type, &opline->extended_value, 1 TSRMLS_CC); - } - class_type->u.constant.value.str.val =
zend_new_interned_string(class_type->u.constant.value.str.val,
class_type->u.constant.value.str.len + 1, 1 TSRMLS_CC); - cur_arg_info->class_name = class_type->u.constant.value.str.val; - cur_arg_info->class_name_len = class_type->u.constant.value.str.len; - if (op == ZEND_RECV_INIT) { - if (Z_TYPE(initialization->u.constant) == IS_NULL ||
(Z_TYPE(initialization->u.constant) == IS_CONSTANT &&
!strcasecmp(Z_STRVAL(initialization->u.constant), "NULL"))) { - cur_arg_info->allow_null = 1; - } else { - zend_error(E_COMPILE_ERROR, "Default value for parameters with a class
type hint can only be NULL"); + if (class_type->u.constant.type == IS_ARRAY) { + cur_arg_info->type_hint = IS_ARRAY; + if (op == ZEND_RECV_INIT) { + if (Z_TYPE(initialization->u.constant) == IS_NULL ||
(Z_TYPE(initialization->u.constant) == IS_CONSTANT &&
!strcasecmp(Z_STRVAL(initialization->u.constant), "NULL"))) { + cur_arg_info->allow_null = 1; + } else if (Z_TYPE(initialization->u.constant) != IS_ARRAY &&
Z_TYPE(initialization->u.constant) != IS_CONSTANT_ARRAY) { + zend_error(E_COMPILE_ERROR, "Default value for parameters with array type
hint can only be an array or NULL"); + } } - } - } else { - cur_arg_info->type_hint = IS_ARRAY; - if (op == ZEND_RECV_INIT) { - if (Z_TYPE(initialization->u.constant) == IS_NULL ||
(Z_TYPE(initialization->u.constant) == IS_CONSTANT &&
!strcasecmp(Z_STRVAL(initialization->u.constant), "NULL"))) { - cur_arg_info->allow_null = 1; - } else if (Z_TYPE(initialization->u.constant) != IS_ARRAY &&
Z_TYPE(initialization->u.constant) != IS_CONSTANT_ARRAY) { - zend_error(E_COMPILE_ERROR, "Default value for parameters with array type
hint can only be an array or NULL"); + } else if (class_type->u.constant.type == IS_CALLABLE) { + char *callable_name; + cur_arg_info->type_hint = IS_CALLABLE; + if (op == ZEND_RECV_INIT) { + if (Z_TYPE(initialization->u.constant) == IS_NULL ||
(Z_TYPE(initialization->u.constant) == IS_CONSTANT &&
!strcasecmp(Z_STRVAL(initialization->u.constant), "NULL"))) { + cur_arg_info->allow_null = 1; + } else { + zend_error(E_COMPILE_ERROR, "Default value for parameters with callable
type hint can only be NULL"); + } } + } else { + cur_arg_info->type_hint = IS_OBJECT; + if (ZEND_FETCH_CLASS_DEFAULT ==
zend_get_class_fetch_type(Z_STRVAL(class_type->u.constant),
Z_STRLEN(class_type->u.constant))) { + zend_resolve_class_name(class_type, &opline->extended_value, 1 TSRMLS_CC); + } + class_type->u.constant.value.str.val =
zend_new_interned_string(class_type->u.constant.value.str.val,
class_type->u.constant.value.str.len + 1, 1 TSRMLS_CC); + cur_arg_info->class_name = class_type->u.constant.value.str.val; + cur_arg_info->class_name_len = class_type->u.constant.value.str.len; + if (op == ZEND_RECV_INIT) { + if (Z_TYPE(initialization->u.constant) == IS_NULL ||
(Z_TYPE(initialization->u.constant) == IS_CONSTANT &&
!strcasecmp(Z_STRVAL(initialization->u.constant), "NULL"))) { + cur_arg_info->allow_null = 1; + } else { + zend_error(E_COMPILE_ERROR, "Default value for parameters with a class
type hint can only be NULL"); + } + } } } } Index: Zend/zend_language_parser.y =================================================================== --- Zend/zend_language_parser.y (revision 311867) +++ Zend/zend_language_parser.y (working copy) @@ -130,6 +130,7 @@ %token T_DOUBLE_ARROW %token T_LIST %token T_ARRAY +%token T_CALLABLE %token T_CLASS_C %token T_METHOD_C %token T_FUNC_C @@ -466,7 +467,8 @@

optional_class_type: /* empty */ { $$.op_type = IS_UNUSED; } - | T_ARRAY { $$.op_type = IS_CONST; Z_TYPE($$.u.constant)=IS_NULL; } + | T_ARRAY { $$.op_type = IS_CONST; Z_TYPE($$.u.constant)=IS_ARRAY; } + | T_CALLABLE { $$.op_type = IS_CONST; Z_TYPE($$.u.constant)=IS_CALLABLE; } | fully_qualified_class_name { $$ = $1; } ;

Index: Zend/tests/callable_type_hint_001.phpt =================================================================== --- Zend/tests/callable_type_hint_001.phpt (revision 0) +++ Zend/tests/callable_type_hint_001.phpt (revision 0) @@ -0,0 +1,40 @@ +--TEST-- +callable type hint#001 +--FILE-- +<?php + +class bar { + function baz() {} + static function foo() {} +} +function foo(callable $bar) { + var_dump($bar); +} +$closure = function () {}; + +foo("strpos"); +foo("foo"); +foo(array("bar", "baz")); +foo(array("bar", "foo")); +foo($closure); +--EXPECTF-- +string(6) "strpos" +string(3) "foo" + +Strict Standards: Non-static method bar::baz() should not be called statically
in %scallable_type_hint_001.php on line %d +array(2) { + [0]=> + string(3) "bar" + [1]=> + string(3) "baz" +} +array(2) { + [0]=> + string(3) "bar" + [1]=> + string(3) "foo" +} +object(Closure)#%d (0) { +} + +