Skip to content

Instantly share code, notes, and snippets.

@ircmaxell
Created March 2, 2012 03:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ircmaxell/1955338 to your computer and use it in GitHub Desktop.
Save ircmaxell/1955338 to your computer and use it in GitHub Desktop.
POC for type casting (same rules as internal variables)
Index: Zend/zend_execute.c
===================================================================
--- Zend/zend_execute.c (revision 322430)
+++ Zend/zend_execute.c (working copy)
@@ -646,7 +646,39 @@
return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", zend_zval_type_name(arg), "" TSRMLS_CC);
}
break;
-
+ case IS_DOUBLE:
+ break;
+ case IS_BOOL:
+ break;
+ case IS_STRING:
+ break;
+ case IS_OBJECT:
+ break;
+ case IS_LONG:
+ if (!arg) {
+ return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type integer", "", "none", "" TSRMLS_CC);
+ }
+ switch (Z_TYPE_P(arg)) {
+ case IS_STRING:
+ {
+ long *p = NULL;
+ double *d = NULL;
+ if (is_numeric_string(Z_STRVAL_P(arg), Z_STRLEN_P(arg), p, d, -1) == 0) {
+ return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type integer", "", zend_zval_type_name(arg), "" TSRMLS_CC);
+ }
+ }
+ /* Fall Through Intentional */
+ case IS_LONG:
+ case IS_BOOL:
+ case IS_NULL:
+ convert_to_long(arg);
+ break;
+ case IS_OBJECT:
+ // TODO: Implement object casting
+ default:
+ return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type integer", "", zend_zval_type_name(arg), "" TSRMLS_CC);
+ }
+ break;
default:
zend_error(E_ERROR, "Unknown typehint");
}
Index: Zend/zend_compile.c
===================================================================
--- Zend/zend_compile.c (revision 322430)
+++ Zend/zend_compile.c (working copy)
@@ -1889,6 +1889,52 @@
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_LONG) {
+ cur_arg_info->type_hint = IS_LONG;
+ 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_LONG) {
+ zend_error(E_COMPILE_ERROR, "Default value for parameters with int type hint can only be INT or NULL");
+ }
+ }
+ } else if (class_type->u.constant.type == IS_DOUBLE) {
+ cur_arg_info->type_hint = IS_DOUBLE;
+ 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_DOUBLE) {
+ zend_error(E_COMPILE_ERROR, "Default value for parameters with float type hint can only be INT or NULL");
+ }
+ }
+ } else if (class_type->u.constant.type == IS_BOOL) {
+ cur_arg_info->type_hint = IS_BOOL;
+ 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_BOOL) {
+ zend_error(E_COMPILE_ERROR, "Default value for parameters with bool type hint can only be INT or NULL");
+ }
+ }
+ } else if (class_type->u.constant.type == IS_OBJECT) {
+ cur_arg_info->type_hint = IS_OBJECT;
+ 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_OBJECT) {
+ zend_error(E_COMPILE_ERROR, "Default value for parameters with object type hint can only be INT or NULL");
+ }
+ }
+ } else if (class_type->u.constant.type == IS_STRING) {
+ cur_arg_info->type_hint = IS_STRING;
+ 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_STRING) {
+ zend_error(E_COMPILE_ERROR, "Default value for parameters with string type hint can only be INT or NULL");
+ }
+ }
+
} else if (class_type->u.constant.type == IS_CALLABLE) {
cur_arg_info->type_hint = IS_CALLABLE;
if (op == ZEND_RECV_INIT) {
@@ -3089,6 +3135,17 @@
} else if (arg_info->type_hint) {
zend_uint type_name_len;
char *type_name = zend_get_type_by_const(arg_info->type_hint);
+ switch (arg_info->type_hint) {
+ case IS_OBJECT:
+ if (arg_info->class_name) {
+ break;
+ }
+ case IS_LONG:
+ case IS_DOUBLE:
+ case IS_BOOL:
+ case IS_STRING:
+ type_name = sprintf("(%s)", type_name);
+ }
type_name_len = strlen(type_name);
REALLOC_BUF_IF_EXCEED(buf, offset, length, type_name_len);
memcpy(offset, type_name, type_name_len);
Index: Zend/zend_language_parser.y
===================================================================
--- Zend/zend_language_parser.y (revision 322430)
+++ Zend/zend_language_parser.y (working copy)
@@ -508,7 +508,6 @@
| /* empty */
;
-
non_empty_parameter_list:
optional_class_type T_VARIABLE { $$.op_type = IS_UNUSED; $$.u.op.num=1; zend_do_receive_arg(ZEND_RECV, &$2, &$$, NULL, &$1, 0 TSRMLS_CC); }
| optional_class_type '&' T_VARIABLE { $$.op_type = IS_UNUSED; $$.u.op.num=1; zend_do_receive_arg(ZEND_RECV, &$3, &$$, NULL, &$1, 1 TSRMLS_CC); }
@@ -525,6 +524,11 @@
/* empty */ { $$.op_type = IS_UNUSED; }
| T_ARRAY { $$.op_type = IS_CONST; Z_TYPE($$.u.constant)=IS_ARRAY; }
| T_CALLABLE { $$.op_type = IS_CONST; Z_TYPE($$.u.constant)=IS_CALLABLE; }
+ | T_BOOL_CAST { $$.op_type = IS_CONST; Z_TYPE($$.u.constant)=IS_BOOL; }
+ | T_INT_CAST { $$.op_type = IS_CONST; Z_TYPE($$.u.constant)=IS_LONG; }
+ | T_DOUBLE_CAST { $$.op_type = IS_CONST; Z_TYPE($$.u.constant)=IS_DOUBLE; }
+ | T_STRING_CAST { $$.op_type = IS_CONST; Z_TYPE($$.u.constant)=IS_STRING; }
+ | T_OBJECT_CAST { $$.op_type = IS_CONST; Z_TYPE($$.u.constant)=IS_OBJECT; }
| fully_qualified_class_name { $$ = $1; }
;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment