Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:34036 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 75662 invoked by uid 1010); 14 Dec 2007 16:19:54 -0000 Delivered-To: ezmlm-scan-internals@lists.php.net Delivered-To: ezmlm-internals@lists.php.net Received: (qmail 75644 invoked from network); 14 Dec 2007 16:19:54 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 14 Dec 2007 16:19:54 -0000 X-Host-Fingerprint: 74.163.146.180 adsl-163-146-180.mia.bellsouth.net Received: from [74.163.146.180] ([74.163.146.180:15507] helo=localhost.localdomain) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 4A/C3-44650-82DA2674 for ; Fri, 14 Dec 2007 11:19:53 -0500 Message-ID: <4A.C3.44650.82DA2674@pb1.pair.com> To: internals@lists.php.net Date: Fri, 14 Dec 2007 11:19:39 -0500 User-Agent: Thunderbird 1.5.0.12 (X11/20070530) MIME-Version: 1.0 References: <97.BF.38526.B657F574@pb1.pair.com> In-Reply-To: <97.BF.38526.B657F574@pb1.pair.com> Content-Type: multipart/mixed; boundary="------------060409090609080307090208" X-Posted-By: 74.163.146.180 Subject: Re: Idea for namespace lookup resolution From: jrhernandez05@gmail.com (Jessie Hernandez) --------------060409090609080307090208 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Attached is the proof-of-concept patch. If the idea is met well, then I'll keep working on it to add caching and, if there's interest, I'll add *namespace imports*. An example of how a class in a namespace that's named the same as an internal class can be loaded: autoload.php test.php I ran a few tests on it and did not find any significant performance hit. If possible, I'd like someone to try it out and see if they have the same result. As always, comments/suggestions on the patch are welcome. Regards, Jessie Hernandez Zend Certified Engineer (http://zend.com/zce.php?c=ZEND006359&r=222727282) Jessie Hernandez wrote: > I just thought of something that might be a solution to the lookup rules > that we currently have in the namespaces implementation. Whether it's > good or not, I just wanted to throw it out there. Here goes: > > Support a user-defined function named __get_namespace_classes, which > will be similar to __autoload. The signature of the function would be > the following: > > > array __get_namespace_classes(string $namespaceName); > > Returns an array of names of classes that are under the specified > namespace, or FALSE if the classes under the namespace could not be > determined. > > > The above function would be used in the lookup rules as follows (using > DateTime as an example): > > 1) Does the class DateTime exist in the current namespace? > 2) If not, and the function __get_namespace_classes exists, call > __get_namespace_classes. > 3) If the string DateTime is returned in the array from > __get_namespace_classes, then autoload that class. > 4) If the class is not in the resulting array, or if the result was > FALSE, then look for an internal class DateTime. > > > With the above function, you can define classes inside your namespace > that are named the same as internal classes without having to explicitly > "use" them all over the place. You also solve the problem of namespace > imports (sorry, use :-) ): > > use PEAR::Net::*; > > $a = new FTP(); > > // The above "use" statement results in calling the > // __get_namespace_classes function and "using" each class in the > // resulting array internally. Meaning the above will be equivalent to > // this: > // > // use PEAR::Net::Curl; > // use PEAR::Net::DNS; > // use PEAR::Net::FTP; > // ...etc... > ?> > > > For the above function to work best, the PHP "dir" function, as an > example, should be modified to have an additional "use_include_path" > argument: > > object dir(string $directory [, bool $use_include_path]) > > > By passing TRUE as the second argument, the directory will be searched > for in the include path. The user can then do something like the > following as an implementation of __get_namespace_classes (assuming the > user organized it into class per file, as is common): > > function __get_namespace_classes($namespaceName) > { > $classes = false; > $nsDir = str_replace( '::', DIRECTORY_SEPARATOR, $namespaceName ); > $d = dir( $nsDir, true ); > > if( $d ) > { > $classes = array(); > > while( ( $file = $d->read() ) !== false ) > $classes[] = str_replace( '.php', '', $file ); > > $d->close(); > } > > return $classes; > } > ?> > > > Let me know what you think! > > > > Regards, > > Jessie --------------060409090609080307090208 Content-Type: text/x-patch; name="gnc_20071214.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="gnc_20071214.patch" Index: Zend/zend_compile.h =================================================================== RCS file: /repository/ZendEngine2/zend_compile.h,v retrieving revision 1.316.2.8.2.12.2.11 diff -u -u -r1.316.2.8.2.12.2.11 zend_compile.h --- Zend/zend_compile.h 13 Dec 2007 10:02:03 -0000 1.316.2.8.2.12.2.11 +++ Zend/zend_compile.h 14 Dec 2007 16:03:52 -0000 @@ -714,6 +714,7 @@ #define ZEND_CALLSTATIC_FUNC_NAME "__callstatic" #define ZEND_TOSTRING_FUNC_NAME "__tostring" #define ZEND_AUTOLOAD_FUNC_NAME "__autoload" +#define ZEND_GET_NAMESPACE_CLASSES_FUNC_NAME "__get_namespace_classes" #endif /* ZEND_COMPILE_H */ Index: Zend/zend_execute_API.c =================================================================== RCS file: /repository/ZendEngine2/zend_execute_API.c,v retrieving revision 1.331.2.20.2.24.2.14 diff -u -u -r1.331.2.20.2.24.2.14 zend_execute_API.c --- Zend/zend_execute_API.c 7 Dec 2007 17:11:23 -0000 1.331.2.20.2.24.2.14 +++ Zend/zend_execute_API.c 14 Dec 2007 16:03:53 -0000 @@ -1592,15 +1592,72 @@ if (zend_lookup_class_ex(class_name, class_name_len, (!rt_ns_check & use_autoload), &pce TSRMLS_CC) == FAILURE) { if (rt_ns_check) { - /* Check if we have internal class with the same name */ + /* check if the __get_namespace_classes function is defined */ + zend_function *func; + zend_bool look_for_internal = 1; char *php_name; uint php_name_len; php_name = zend_memrchr(class_name, ':', class_name_len); + if (php_name) { + char *ns_name = php_name; + uint ns_name_len; + php_name++; php_name_len = class_name_len - (php_name - class_name); php_name = zend_str_tolower_dup(php_name, php_name_len); + + if (zend_hash_find(EG(function_table), ZEND_GET_NAMESPACE_CLASSES_FUNC_NAME, sizeof(ZEND_GET_NAMESPACE_CLASSES_FUNC_NAME), (void **)&func) == SUCCESS) { + zval class_name_zv; + zval *class_name_ptr; + zval get_namespace_classes_function; + zval **gnc_args[1]; + zend_bool gnc_callretval; + zval *gnc_retval_ptr; + + ns_name_len = ns_name - class_name - 1; + + ZVAL_STRINGL(&class_name_zv, class_name, ns_name_len - 1, 0); + ZVAL_STRINGL(&get_namespace_classes_function, ZEND_GET_NAMESPACE_CLASSES_FUNC_NAME, sizeof(ZEND_GET_NAMESPACE_CLASSES_FUNC_NAME) - 1, 0); + + class_name_ptr = &class_name_zv; + gnc_args[0] = &class_name_ptr; + + /* call the __get_namespace_classes function */ + gnc_callretval = call_user_function_ex(EG(function_table), NULL, &get_namespace_classes_function, &gnc_retval_ptr, 1, gnc_args, 1, NULL TSRMLS_CC); + + if (Z_TYPE_P(gnc_retval_ptr) == IS_ARRAY ) { + zval **entry; + zend_bool found_class = 0; + HashPosition pos; + HashTable *target_hash = Z_ARRVAL_P(gnc_retval_ptr); + + /* iterate through the values to see if the class was returned */ + zend_hash_internal_pointer_reset_ex(target_hash, &pos); + while (zend_hash_get_current_data_ex(target_hash, (void **)&entry, &pos) == SUCCESS) { + zend_str_tolower(Z_STRVAL_PP(entry), Z_STRLEN_PP(entry)); + if (strncmp(Z_STRVAL_PP(entry), php_name, php_name_len) == 0) { + found_class = 1; + look_for_internal = 0; + efree(php_name); + break; + } + zend_hash_move_forward_ex(target_hash, &pos); + } + + /* if the class was not in the returned array, then don't attempt to autoload it, + since it doesn't exist in the namespace */ + if (!found_class) { + use_autoload = 0; + } + } + zval_ptr_dtor(&gnc_retval_ptr); + } + } + + if (look_for_internal) { + /* Check if we have internal class with the same name */ if (zend_hash_find(EG(class_table), php_name, php_name_len + 1, (void **) &pce) == SUCCESS && (*pce)->type == ZEND_INTERNAL_CLASS ) { --------------060409090609080307090208--