Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:40476 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 60120 invoked from network); 12 Sep 2008 02:14:18 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 12 Sep 2008 02:14:18 -0000 Authentication-Results: pb1.pair.com smtp.mail=greg@chiaraquartet.net; spf=permerror; sender-id=unknown Authentication-Results: pb1.pair.com header.from=greg@chiaraquartet.net; sender-id=unknown Received-SPF: error (pb1.pair.com: domain chiaraquartet.net from 208.83.222.18 cause and error) X-PHP-List-Original-Sender: greg@chiaraquartet.net X-Host-Fingerprint: 208.83.222.18 unknown Linux 2.6 Received: from [208.83.222.18] ([208.83.222.18:51538] helo=mail.bluga.net) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 96/A1-49770-970D9C84 for ; Thu, 11 Sep 2008 22:14:18 -0400 Received: from mail.bluga.net (localhost.localdomain [127.0.0.1]) by mail.bluga.net (Postfix) with ESMTP id 56A18C0E249 for ; Thu, 11 Sep 2008 19:13:28 -0700 (MST) Received: from [192.168.223.130] (CPE-76-84-4-101.neb.res.rr.com [76.84.4.101]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mail.bluga.net (Postfix) with ESMTP id A4D33C0E246 for ; Thu, 11 Sep 2008 19:13:27 -0700 (MST) Message-ID: <48C9D075.9090708@chiaraquartet.net> Date: Thu, 11 Sep 2008 21:14:13 -0500 User-Agent: Thunderbird 2.0.0.16 (X11/20080724) MIME-Version: 1.0 To: internals@lists.php.net Content-Type: multipart/mixed; boundary="------------030305050407030105090500" X-Virus-Scanned: ClamAV using ClamSMTP Subject: [PATCH] add support for functions to use From: greg@chiaraquartet.net (Greg Beaver) --------------030305050407030105090500 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Hi, I've just finished implementing use for functions. This patch is against PHP_5_3 and can be easily ported to HEAD. I am confident that it is quite mature and have tests in the patch to prove it. the patch is also at http://pear.php.net/~greg/usefunctions.patch.txt This patch implements the following syntax: func.inc: main.php: The output is "hi\nhi\nhi\n" It can be used to alias any function, and so can also be useful for overriding an internal function and saving it: With this patch, function users should be a lot happier. Thanks, Greg --------------030305050407030105090500 Content-Type: text/plain; name="usefunctions.patch.txt" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="usefunctions.patch.txt" Index: Zend/zend_compile.c =================================================================== RCS file: /repository/ZendEngine2/zend_compile.c,v retrieving revision 1.647.2.27.2.41.2.85 diff -u -u -r1.647.2.27.2.41.2.85 zend_compile.c --- Zend/zend_compile.c 29 Aug 2008 10:17:08 -0000 1.647.2.27.2.41.2.85 +++ Zend/zend_compile.c 12 Sep 2008 01:56:14 -0000 @@ -139,6 +139,7 @@ CG(start_lineno) = 0; CG(current_namespace) = NULL; CG(current_import) = NULL; + CG(current_import_functions) = NULL; init_compiler_declarables(TSRMLS_C); zend_hash_apply(CG(auto_globals), (apply_func_t) zend_auto_global_arm TSRMLS_CC); zend_stack_init(&CG(labels_stack)); @@ -1536,22 +1537,10 @@ char *lcname; int prefix_len = 0; - if (check_namespace && CG(current_namespace)) { - /* We assume we call function from the current namespace - if it is not prefixed. */ - znode tmp; - - tmp.op_type = IS_CONST; - tmp.u.constant = *CG(current_namespace); - zval_copy_ctor(&tmp.u.constant); - zend_do_build_namespace_name(&tmp, &tmp, function_name TSRMLS_CC); - *function_name = tmp; - - /* In run-time PHP will check for function with full name and - internal function with short name */ - prefix_len = Z_STRLEN_P(CG(current_namespace)) + 2; + if (check_namespace) { + zend_resolve_function_name(function_name, &prefix_len TSRMLS_CC); } - + lcname = zend_str_tolower_dup(function_name->u.constant.value.str.val, function_name->u.constant.value.str.len); if ((zend_hash_find(CG(function_table), lcname, function_name->u.constant.value.str.len+1, (void **) &function)==FAILURE) || ((CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS) && @@ -1672,6 +1661,55 @@ zend_do_extended_fcall_begin(TSRMLS_C); } +void zend_resolve_function_name(znode *function_name, int *prefix_len TSRMLS_DC) +{ + char *compound; + char *lcname; + zval **ns; + znode tmp; + + compound = memchr(Z_STRVAL(function_name->u.constant), ':', Z_STRLEN(function_name->u.constant)); + if (compound) { + /* This is a compound function name that contains namespace prefix */ + if (Z_TYPE(function_name->u.constant) == IS_STRING && + Z_STRVAL(function_name->u.constant)[0] == ':') { + /* The STRING name has "::" prefix */ + Z_STRLEN(function_name->u.constant) -= 2; + memmove(Z_STRVAL(function_name->u.constant), Z_STRVAL(function_name->u.constant)+2, Z_STRLEN(function_name->u.constant)+1); + Z_STRVAL(function_name->u.constant) = erealloc( + Z_STRVAL(function_name->u.constant), + Z_STRLEN(function_name->u.constant) + 1); + + /* check for self/parent/etc. */ + if (ZEND_FETCH_CLASS_DEFAULT != zend_get_class_fetch_type(Z_STRVAL(function_name->u.constant), Z_STRLEN(function_name->u.constant))) { + zend_error(E_COMPILE_ERROR, "'::%s' is a wrong function name", Z_STRVAL(function_name->u.constant)); + } + } + } else if (CG(current_import_functions) || CG(current_namespace)) { + /* this is a plain name (without ::) */ + lcname = zend_str_tolower_dup(Z_STRVAL(function_name->u.constant), Z_STRLEN(function_name->u.constant)); + + if (CG(current_import_functions) && + zend_hash_find(CG(current_import_functions), lcname, Z_STRLEN(function_name->u.constant)+1, (void**)&ns) == SUCCESS) { + /* The given name is an import name. Substitute it. */ + zval_dtor(&function_name->u.constant); + function_name->u.constant = **ns; + zval_copy_ctor(&function_name->u.constant); + } else if (CG(current_namespace)) { + tmp.op_type = IS_CONST; + tmp.u.constant = *CG(current_namespace); + zval_copy_ctor(&tmp.u.constant); + zend_do_build_namespace_name(&tmp, &tmp, function_name TSRMLS_CC); + *function_name = tmp; + + /* In run-time PHP will check for function with full name and + internal function with short name */ + *prefix_len = Z_STRLEN_P(CG(current_namespace)) + 2; + } + efree(lcname); + } +} + void zend_resolve_class_name(znode *class_name, ulong *fetch_type, int check_ns_name TSRMLS_DC) { char *compound; @@ -5075,16 +5113,26 @@ } /* }}} */ -void zend_do_use(znode *ns_name, znode *new_name, int is_global TSRMLS_DC) /* {{{ */ +void zend_do_use(znode *ns_name, znode *new_name, int is_global, int is_function TSRMLS_DC) /* {{{ */ { char *lcname; zval *name, *ns, tmp; zend_bool warn = 0; zend_class_entry **pce; + zend_function *func; + HashTable **import, *other; - if (!CG(current_import)) { - CG(current_import) = emalloc(sizeof(HashTable)); - zend_hash_init(CG(current_import), 0, NULL, ZVAL_PTR_DTOR, 0); + if (is_function) { + import = &CG(current_import_functions); + other = CG(current_import); + } else { + import = &CG(current_import); + other = CG(current_import_functions); + } + + if (!*import) { + *import = emalloc(sizeof(HashTable)); + zend_hash_init(*import, 0, NULL, ZVAL_PTR_DTOR, 0); } ALLOC_ZVAL(ns); @@ -5124,8 +5172,12 @@ ns_name[Z_STRLEN_P(CG(current_namespace))] = ':'; ns_name[Z_STRLEN_P(CG(current_namespace))+1] = ':'; memcpy(ns_name+Z_STRLEN_P(CG(current_namespace))+2, lcname, Z_STRLEN_P(name)+1); - if (zend_hash_exists(CG(class_table), ns_name, Z_STRLEN_P(CG(current_namespace)) + 2 + Z_STRLEN_P(name)+1)) { - char *tmp = zend_str_tolower_dup(Z_STRVAL_P(ns), Z_STRLEN_P(ns)); + if (is_function && zend_hash_exists(CG(function_table), ns_name, Z_STRLEN_P(CG(current_namespace)) + 2 + Z_STRLEN_P(name)+1)) { + goto conflict_error; + } else if (!is_function && zend_hash_exists(CG(class_table), ns_name, Z_STRLEN_P(CG(current_namespace)) + 2 + Z_STRLEN_P(name)+1)) { + char *tmp; +conflict_error: + tmp = zend_str_tolower_dup(Z_STRVAL_P(ns), Z_STRLEN_P(ns)); if (Z_STRLEN_P(ns) != Z_STRLEN_P(CG(current_namespace)) + 2 + Z_STRLEN_P(name) || memcmp(tmp, ns_name, Z_STRLEN_P(ns))) { @@ -5134,10 +5186,16 @@ efree(tmp); } efree(ns_name); - } else if (zend_hash_find(CG(class_table), lcname, Z_STRLEN_P(name)+1, (void**)&pce) == SUCCESS && + } else if (is_function && zend_hash_find(CG(function_table), lcname, Z_STRLEN_P(name)+1, (void**)&func) == SUCCESS && + func->common.type == ZEND_USER_FUNCTION && + func->op_array.filename == CG(compiled_filename)) { + goto use_in_use; + } else if (!is_function && zend_hash_find(CG(class_table), lcname, Z_STRLEN_P(name)+1, (void**)&pce) == SUCCESS && (*pce)->type == ZEND_USER_CLASS && (*pce)->filename == CG(compiled_filename)) { - char *tmp = zend_str_tolower_dup(Z_STRVAL_P(ns), Z_STRLEN_P(ns)); + char *tmp; +use_in_use: + tmp = zend_str_tolower_dup(Z_STRVAL_P(ns), Z_STRLEN_P(ns)); if (Z_STRLEN_P(ns) != Z_STRLEN_P(name) || memcmp(tmp, lcname, Z_STRLEN_P(ns))) { @@ -5146,7 +5204,11 @@ efree(tmp); } - if (zend_hash_add(CG(current_import), lcname, Z_STRLEN_P(name)+1, &ns, sizeof(zval*), NULL) != SUCCESS) { + if (other && zend_hash_exists(other, lcname, Z_STRLEN_P(name)+1)) { + goto use_in_use2; + } + if (zend_hash_add(*import, lcname, Z_STRLEN_P(name)+1, &ns, sizeof(zval*), NULL) != SUCCESS) { +use_in_use2: zend_error(E_COMPILE_ERROR, "Cannot use %s as %s because the name is already in use", Z_STRVAL_P(ns), Z_STRVAL_P(name)); } if (warn) { @@ -5200,6 +5262,11 @@ efree(CG(current_import)); CG(current_import) = NULL; } + if (CG(current_import_functions)) { + zend_hash_destroy(CG(current_import_functions)); + efree(CG(current_import_functions)); + CG(current_import_functions) = NULL; + } } /* }}} */ Index: Zend/zend_compile.h =================================================================== RCS file: /repository/ZendEngine2/zend_compile.h,v retrieving revision 1.316.2.8.2.12.2.33 diff -u -u -r1.316.2.8.2.12.2.33 zend_compile.h --- Zend/zend_compile.h 29 Aug 2008 18:12:47 -0000 1.316.2.8.2.12.2.33 +++ Zend/zend_compile.h 12 Sep 2008 01:56:15 -0000 @@ -360,6 +360,7 @@ ZEND_API size_t zend_get_scanned_file_offset(TSRMLS_D); void zend_resolve_class_name(znode *class_name, ulong *fetch_type, int check_ns_name TSRMLS_DC); +void zend_resolve_function_name(znode *function_name, int *prefix_len TSRMLS_DC); ZEND_API char* zend_get_compiled_variable_name(const zend_op_array *op_array, zend_uint var, int* name_len); #ifdef ZTS @@ -537,7 +538,7 @@ void zend_do_declare_constant(znode *name, znode *value TSRMLS_DC); void zend_do_build_namespace_name(znode *result, znode *prefix, znode *name TSRMLS_DC); void zend_do_namespace(const znode *name TSRMLS_DC); -void zend_do_use(znode *name, znode *new_name, int is_global TSRMLS_DC); +void zend_do_use(znode *name, znode *new_name, int is_global, int is_function TSRMLS_DC); void zend_do_end_compilation(TSRMLS_D); void zend_do_label(znode *label TSRMLS_DC); Index: Zend/zend_globals.h =================================================================== RCS file: /repository/ZendEngine2/zend_globals.h,v retrieving revision 1.141.2.3.2.7.2.19 diff -u -u -r1.141.2.3.2.7.2.19 zend_globals.h --- Zend/zend_globals.h 14 Aug 2008 10:24:51 -0000 1.141.2.3.2.7.2.19 +++ Zend/zend_globals.h 12 Sep 2008 01:56:18 -0000 @@ -134,6 +134,7 @@ zval *current_namespace; HashTable *current_import; + HashTable *current_import_functions; HashTable *labels; zend_stack labels_stack; Index: Zend/zend_language_parser.y =================================================================== RCS file: /repository/ZendEngine2/zend_language_parser.y,v retrieving revision 1.160.2.4.2.8.2.26 diff -u -u -r1.160.2.4.2.8.2.26 zend_language_parser.y --- Zend/zend_language_parser.y 29 Aug 2008 17:54:29 -0000 1.160.2.4.2.8.2.26 +++ Zend/zend_language_parser.y 12 Sep 2008 01:56:23 -0000 @@ -164,6 +164,11 @@ | namespace_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_build_namespace_name(&$$, &$1, &$3 TSRMLS_CC); } ; +compound_namespace_name: + T_STRING T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_build_namespace_name(&$$, &$1, &$3 TSRMLS_CC); } + | compound_namespace_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_build_namespace_name(&$$, &$1, &$3 TSRMLS_CC); } +; + top_statement: statement | function_declaration_statement { zend_do_early_binding(TSRMLS_C); } @@ -180,10 +185,14 @@ ; use_declaration: - namespace_name { zend_do_use(&$1, NULL, 0 TSRMLS_CC); } - | namespace_name T_AS T_STRING { zend_do_use(&$1, &$3, 0 TSRMLS_CC); } - | T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_use(&$2, NULL, 1 TSRMLS_CC); } - | T_PAAMAYIM_NEKUDOTAYIM T_STRING T_AS T_STRING { zend_do_use(&$2, &$4, 1 TSRMLS_CC); } + namespace_name { zend_do_use(&$1, NULL, 0, 0 TSRMLS_CC); } + | T_FUNCTION T_PAAMAYIM_NEKUDOTAYIM compound_namespace_name { zend_do_use(&$3, NULL, 0, 1 TSRMLS_CC); } + | namespace_name T_AS T_STRING { zend_do_use(&$1, &$3, 0, 0 TSRMLS_CC); } + | T_FUNCTION T_PAAMAYIM_NEKUDOTAYIM compound_namespace_name T_AS T_STRING { zend_do_use(&$3, &$5, 0, 1 TSRMLS_CC); } + | T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_use(&$2, NULL, 1, 0 TSRMLS_CC); } + | T_FUNCTION T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_use(&$3, NULL, 1, 1 TSRMLS_CC); } + | T_PAAMAYIM_NEKUDOTAYIM T_STRING T_AS T_STRING { zend_do_use(&$2, &$4, 1, 0 TSRMLS_CC); } + | T_FUNCTION T_PAAMAYIM_NEKUDOTAYIM T_STRING T_AS T_STRING { zend_do_use(&$3, &$5, 1, 1 TSRMLS_CC); } ; constant_declaration: Index: Zend/tests/ns_072.phpt =================================================================== RCS file: Zend/tests/ns_072.phpt diff -N Zend/tests/ns_072.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/ns_072.phpt 12 Sep 2008 01:57:04 -0000 @@ -0,0 +1,19 @@ +--TEST-- +072: use for namespace functions +--FILE-- + +===DONE=== +--EXPECT-- +hi +hi +===DONE=== Index: Zend/tests/ns_073.inc =================================================================== RCS file: Zend/tests/ns_073.inc diff -N Zend/tests/ns_073.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/ns_073.inc 12 Sep 2008 01:57:04 -0000 @@ -0,0 +1,11 @@ + \ No newline at end of file Index: Zend/tests/ns_073.phpt =================================================================== RCS file: Zend/tests/ns_073.phpt diff -N Zend/tests/ns_073.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/ns_073.phpt 12 Sep 2008 01:57:04 -0000 @@ -0,0 +1,13 @@ +--TEST-- +073: use for namespace functions +--FILE-- + +===DONE=== +--EXPECT-- +hi +hi +===DONE=== Index: Zend/tests/ns_074.phpt =================================================================== RCS file: Zend/tests/ns_074.phpt diff -N Zend/tests/ns_074.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/ns_074.phpt 12 Sep 2008 01:57:04 -0000 @@ -0,0 +1,11 @@ +--TEST-- +074: use static +--FILE-- + +===DONE=== +--EXPECTF-- +Fatal error: Cannot use one::parent as parent because 'parent' is a special class name in %sns_074.php on line %d \ No newline at end of file Index: Zend/tests/ns_075.phpt =================================================================== RCS file: Zend/tests/ns_075.phpt diff -N Zend/tests/ns_075.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/ns_075.phpt 12 Sep 2008 01:57:04 -0000 @@ -0,0 +1,11 @@ +--TEST-- +075: use for namespace functions +--FILE-- + +===DONE=== +--EXPECT-- +12 +===DONE=== Index: Zend/tests/ns_076.phpt =================================================================== RCS file: Zend/tests/ns_076.phpt diff -N Zend/tests/ns_076.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/ns_076.phpt 12 Sep 2008 01:57:04 -0000 @@ -0,0 +1,12 @@ +--TEST-- +076: use for namespace functions +--FILE-- + +===DONE=== +--EXPECT-- +13 +===DONE=== --------------030305050407030105090500--