Hello. After a short bout of hair-pulling, I have discovered the source (in the Zend engine) of a recent problem, and have fixed it.
BACKGROUND: As I have mentioned previously on this list, I am developing a complex PHP extension, which among many other things creates its own PHP classes, and when these classes are instantiated, I manually call the class constructor (as one must) from my C code. I am creating the extension from existing C++ and Java versions of the same system, so I am trying to maintain things as much as possible, including names (including capitalization) of classes and functions (although I am prefixing them all with "eo_" to avoid potential conflicts with functions and classes from other PHP extensions). Thus, I have classes such as "eo_list", "eo_table" and "eo_NVList". THE SYMPTOM: I had no trouble instantiating and calling the constructors for the first two classes, but when I tried to do it for eo_NVList, call_user_function_ex() was returning FAILURE, which I discovered can occur for one of seven reasons. I tracked down the problem to a failure of zend_hash_find() to lookup the function. Using zend_hash_display() I was able to verify that the eo_NVList constructor was indeed contained in the function table for the eo_NVList class. THE PROBLEM: call_user_function_ex() is converting the requested function name to lower case (at zend_execute_API.c:463) before performing the zend_hash_find(), but zend_register_functions() (in zend_API.c) does NOT convert the function names to lower case before storing them in the function table--so call_user_function_ex() was searching for a function called "eo_nvlist" and could never find "eo_NVList"! Class lookups worked fine of course, because object_init_ex() takes a pointer to the class entry rather than a name. Additionally, zend_register_internal_class() (also in zend_API.c) converts all class names to lower case, and execute() (in zend_execute.c) does the same when looking up a class to instantiate it from a script. I haven't looked into script-driven function registration and execution, but presumably case-insensitivity is properly supported there, or I'm sure you would have heard of it long ago! MY SOLUTION: I present the following little patch for your approval. I apologize that it is done against 4.3.1 rather than the latest CVS but I do not have time to deal with CVS at this time, as my project is already behind schedule and of course I need to work with a stable engine. If zend_API.c has changed since the 4.3.1 release, it should be trivial to change these few lines of code (yes, I'm sure they all say that!). =) I didn't find any patch submission guidlines in a quick web search; I'm afraid you'll have to change the file/pathnames in the first lines. If you don't want to deal with that, point me to the guidelines and I will resubmit the patch. For now I will get back to work. Respectfully, Eric Lambart --- Zend/OLD_zend_API.c Wed Oct 9 07:17:52 2002 +++ Zend/zend_API.c Fri Mar 7 13:10:38 2003 @@ -1039,6 +1039,12 @@ internal_function->type = ZEND_INTERNAL_FUNCTION; while (ptr->fname) { + /* store all function names in lower case so they will always be found by + * call_user_function_ex() */ + size_t fname_len = strlen(ptr->fname); + char *lowercase_name = zend_strndup(ptr->fname, fname_len); + zend_str_tolower(lowercase_name, fname_len); + internal_function->handler = ptr->handler; internal_function->arg_types = ptr->func_arg_types; internal_function->function_name = ptr->fname; @@ -1047,7 +1053,7 @@ zend_unregister_functions(functions, count, target_function_table TSRMLS_CC); return FAILURE; } - if (zend_hash_add(target_function_table, ptr->fname, strlen(ptr->fname)+1, &function, sizeof(zend_function), NULL) == FAILURE) { + if (zend_hash_add(target_function_table, lowercase_name, fname_len+1, &function, sizeof(zend_function), NULL) == FAILURE) { unload=1; break; } -- PHP Development Mailing List <http://www.php.net/> To unsubscribe, visit: http://www.php.net/unsub.php