Hi again, The attached patches for PHP 5.3 and PHP 6 add in_class_exists(). The function is intended to be used in __autoload(). The following test script demonstrates its usage:
<?php var_dump(in_class_exists('test')); function __autoload($class) { var_dump(in_class_exists($class)); eval ('class ' . $class . ' {}'); } $a = new Bungalow; // autoload called, not because of class_exists(), bool(false) class_exists('test'); // autoload called because of class_exists(), bool(true) class_exists('test'); // class exists, no autoload, no output $a = new test; // autoload not called, no output $a = new Another; // autoload called, not because of class_exists(), bool(false) ?> outputting: bool(false) bool(false) bool(true) bool(false) The purpose is to allow an autoload handler to detect whether it is safe to use die() or some other method of terminating execution. A user calling class_exists() clearly expects a return from autoload, whereas a user instantiating an object will expect a fatal error if the class cannot be found. This is useful for PEAR2 as a means of displaying helpful information on locating missing class files only in cases where a fatal error would result anyways. Thanks, Greg
Index: Zend/zend_builtin_functions.c =================================================================== RCS file: /repository/ZendEngine2/zend_builtin_functions.c,v retrieving revision 1.277.2.12.2.25.2.3 diff -u -r1.277.2.12.2.25.2.3 zend_builtin_functions.c --- Zend/zend_builtin_functions.c 29 Sep 2007 07:28:32 -0000 1.277.2.12.2.25.2.3 +++ Zend/zend_builtin_functions.c 3 Oct 2007 06:07:33 -0000 @@ -48,6 +48,7 @@ static ZEND_FUNCTION(method_exists); static ZEND_FUNCTION(property_exists); static ZEND_FUNCTION(class_exists); +static ZEND_FUNCTION(in_class_exists); static ZEND_FUNCTION(interface_exists); static ZEND_FUNCTION(function_exists); #if ZEND_DEBUG @@ -109,6 +110,7 @@ ZEND_FE(method_exists, NULL) ZEND_FE(property_exists, NULL) ZEND_FE(class_exists, NULL) + ZEND_FE(in_class_exists, NULL) ZEND_FE(interface_exists, NULL) ZEND_FE(function_exists, NULL) #if ZEND_DEBUG @@ -1026,6 +1028,29 @@ } /* }}} */ +/* {{{ proto bool in_class_exists(string classname) + Checks if __autoload was called by class_exists() or interface_exists() +*/ +ZEND_FUNCTION(in_class_exists) +{ + char *class_name; + int class_name_len; + char *lc_name; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &class_name, &class_name_len) == FAILURE) { + return; + } + + if (EG(in_class_exists) == NULL) { + RETURN_FALSE; + } + + lc_name = do_alloca(class_name_len + 1); + zend_str_tolower_copy(lc_name, class_name, class_name_len); + + RETURN_BOOL(zend_hash_exists(EG(in_class_exists), lc_name, class_name_len + 1)); +} +/* }}} */ /* {{{ proto bool class_exists(string classname [, bool autoload]) Checks if the class exists */ @@ -1036,23 +1061,36 @@ int class_name_len; zend_bool autoload = 1; int found; + char dummy = 1; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &class_name, &class_name_len, &autoload) == FAILURE) { return; } + lc_name = do_alloca(class_name_len + 1); + zend_str_tolower_copy(lc_name, class_name, class_name_len); + if (!autoload) { - lc_name = do_alloca(class_name_len + 1); - zend_str_tolower_copy(lc_name, class_name, class_name_len); - found = zend_hash_find(EG(class_table), lc_name, class_name_len+1, (void **) &ce); free_alloca(lc_name); RETURN_BOOL(found == SUCCESS && !((*ce)->ce_flags & ZEND_ACC_INTERFACE)); } + if (EG(in_class_exists) == NULL) { + ALLOC_HASHTABLE(EG(in_class_exists)); + zend_hash_init(EG(in_class_exists), 0, NULL, NULL, 0); + } + + zend_hash_add(EG(in_class_exists), lc_name, class_name_len+1, (void**)&dummy, sizeof(char), NULL); + if (zend_lookup_class(class_name, class_name_len, &ce TSRMLS_CC) == SUCCESS) { + zend_hash_del(EG(in_class_exists), lc_name, class_name_len+1); + free_alloca(lc_name); RETURN_BOOL(((*ce)->ce_flags & ZEND_ACC_INTERFACE) == 0); } else { + zend_printf("\n%s 3.5\n", lc_name); + zend_hash_del(EG(in_class_exists), lc_name, class_name_len+1); + free_alloca(lc_name); RETURN_FALSE; } } @@ -1067,23 +1105,36 @@ int iface_name_len; zend_bool autoload = 1; int found; + char dummy = 1; + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &iface_name, &iface_name_len, &autoload) == FAILURE) { return; } + lc_name = do_alloca(iface_name_len + 1); + zend_str_tolower_copy(lc_name, iface_name, iface_name_len); + if (!autoload) { - lc_name = do_alloca(iface_name_len + 1); - zend_str_tolower_copy(lc_name, iface_name, iface_name_len); - found = zend_hash_find(EG(class_table), lc_name, iface_name_len+1, (void **) &ce); free_alloca(lc_name); RETURN_BOOL(found == SUCCESS && (*ce)->ce_flags & ZEND_ACC_INTERFACE); } + if (EG(in_class_exists) == NULL) { + ALLOC_HASHTABLE(EG(in_class_exists)); + zend_hash_init(EG(in_class_exists), 0, NULL, NULL, 0); + } + + zend_hash_add(EG(in_class_exists), lc_name, iface_name_len+1, (void**)&dummy, sizeof(char), NULL); + if (zend_lookup_class(iface_name, iface_name_len, &ce TSRMLS_CC) == SUCCESS) { + zend_hash_del(EG(in_class_exists), lc_name, iface_name_len+1); + free_alloca(lc_name); RETURN_BOOL(((*ce)->ce_flags & ZEND_ACC_INTERFACE) > 0); } else { + zend_hash_del(EG(in_class_exists), lc_name, iface_name_len+1); + free_alloca(lc_name); RETURN_FALSE; } } Index: Zend/zend_execute_API.c =================================================================== RCS file: /repository/ZendEngine2/zend_execute_API.c,v retrieving revision 1.331.2.20.2.24.2.6 diff -u -r1.331.2.20.2.24.2.6 zend_execute_API.c --- Zend/zend_execute_API.c 2 Oct 2007 08:26:48 -0000 1.331.2.20.2.24.2.6 +++ Zend/zend_execute_API.c 3 Oct 2007 06:07:37 -0000 @@ -143,6 +143,7 @@ EG(in_execution) = 0; EG(in_autoload) = NULL; + EG(in_class_exists) = NULL; EG(autoload_func) = NULL; zend_ptr_stack_init(&EG(argument_stack)); @@ -320,6 +321,10 @@ zend_hash_destroy(EG(in_autoload)); FREE_HASHTABLE(EG(in_autoload)); } + if (EG(in_class_exists)) { + zend_hash_destroy(EG(in_class_exists)); + FREE_HASHTABLE(EG(in_class_exists)); + } } zend_end_try(); EG(active) = 0; } Index: Zend/zend_globals.h =================================================================== RCS file: /repository/ZendEngine2/zend_globals.h,v retrieving revision 1.141.2.3.2.7.2.3 diff -u -r1.141.2.3.2.7.2.3 zend_globals.h --- Zend/zend_globals.h 29 Sep 2007 07:28:33 -0000 1.141.2.3.2.7.2.3 +++ Zend/zend_globals.h 3 Oct 2007 06:07:37 -0000 @@ -199,6 +199,7 @@ int ticks_count; zend_bool in_execution; + HashTable *in_class_exists; HashTable *in_autoload; zend_function *autoload_func; zend_bool full_tables_cleanup;
Index: Zend/zend_builtin_functions.c =================================================================== RCS file: /repository/ZendEngine2/zend_builtin_functions.c,v retrieving revision 1.355 diff -u -r1.355 zend_builtin_functions.c --- Zend/zend_builtin_functions.c 29 Sep 2007 02:08:19 -0000 1.355 +++ Zend/zend_builtin_functions.c 3 Oct 2007 06:12:25 -0000 @@ -47,6 +47,7 @@ static ZEND_FUNCTION(get_parent_class); static ZEND_FUNCTION(method_exists); static ZEND_FUNCTION(property_exists); +static ZEND_FUNCTION(in_class_exists); static ZEND_FUNCTION(class_exists); static ZEND_FUNCTION(interface_exists); static ZEND_FUNCTION(function_exists); @@ -108,7 +109,8 @@ ZEND_FE(get_parent_class, NULL) ZEND_FE(method_exists, NULL) ZEND_FE(property_exists, NULL) - ZEND_FE(class_exists, NULL) + ZEND_FE(in_class_exists, NULL) + ZEND_FE(class_exists, NULL) ZEND_FE(interface_exists, NULL) ZEND_FE(function_exists, NULL) #if ZEND_DEBUG @@ -1061,6 +1063,33 @@ } /* }}} */ +/* {{{ proto bool in_class_exists(string classname [, bool autoload]) U + Checks if __autoload was called by class_exists() or interface_exists() +*/ +ZEND_FUNCTION(in_class_exists) +{ + zstr class_name, lc_name; + zend_uchar type; + unsigned int lc_name_len; + int class_name_len; + int result; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "t", &class_name, &class_name_len, &type) == FAILURE) { + return; + } + + if (EG(in_class_exists) == NULL) { + RETURN_FALSE; + } + + lc_name = zend_u_str_case_fold(type, class_name, class_name_len, 1, &lc_name_len); + + result = zend_u_hash_exists(EG(in_class_exists), type, lc_name, lc_name_len + 1); + efree(lc_name.v); + RETURN_BOOL(result); +} +/* }}} */ + /* {{{ proto bool class_exists(string classname [, bool autoload]) U Checks if the class exists */ ZEND_FUNCTION(class_exists) @@ -1070,6 +1099,7 @@ zend_class_entry **ce; int class_name_len; zend_bool autoload = 1; + char dummy = 1; zend_uchar type; int found; @@ -1077,16 +1107,27 @@ return; } + lc_name = zend_u_str_case_fold(type, class_name, class_name_len, 1, &lc_name_len); if (!autoload) { - lc_name = zend_u_str_case_fold(type, class_name, class_name_len, 1, &lc_name_len); found = zend_u_hash_find(EG(class_table), type, lc_name, lc_name_len+1, (void **) &ce); efree(lc_name.v); RETURN_BOOL(found == SUCCESS && !((*ce)->ce_flags & ZEND_ACC_INTERFACE)); } + if (EG(in_class_exists) == NULL) { + ALLOC_HASHTABLE(EG(in_class_exists)); + zend_u_hash_init(EG(in_class_exists), 0, NULL, NULL, 0, UG(unicode)); + } + + zend_u_hash_add(EG(in_class_exists), type, lc_name, class_name_len+1, (void**)&dummy, sizeof(char), NULL); + if (zend_u_lookup_class(type, class_name, class_name_len, &ce TSRMLS_CC) == SUCCESS) { + zend_u_hash_del(EG(in_class_exists), type, lc_name, class_name_len+1); + efree(lc_name.v); RETURN_BOOL(((*ce)->ce_flags & ZEND_ACC_INTERFACE) == 0); } else { + zend_u_hash_del(EG(in_class_exists), type, lc_name, class_name_len+1); + efree(lc_name.v); RETURN_FALSE; } } @@ -1101,6 +1142,7 @@ zend_class_entry **ce; int iface_name_len; zend_uchar type; + char dummy = 1; zend_bool autoload = 1; int found; @@ -1108,16 +1150,27 @@ return; } + lc_name = zend_u_str_case_fold(type, iface_name, iface_name_len, 1, &lc_name_len); if (!autoload) { - lc_name = zend_u_str_case_fold(type, iface_name, iface_name_len, 1, &lc_name_len); found = zend_u_hash_find(EG(class_table), type, lc_name, lc_name_len+1, (void **) &ce); efree(lc_name.v); RETURN_BOOL(found == SUCCESS && (*ce)->ce_flags & ZEND_ACC_INTERFACE); } + if (EG(in_class_exists) == NULL) { + ALLOC_HASHTABLE(EG(in_class_exists)); + zend_u_hash_init(EG(in_class_exists), 0, NULL, NULL, 0, UG(unicode)); + } + + zend_u_hash_add(EG(in_class_exists), type, lc_name, iface_name_len+1, (void**)&dummy, sizeof(char), NULL); + if (zend_u_lookup_class(type, iface_name, iface_name_len, &ce TSRMLS_CC) == SUCCESS) { + zend_u_hash_del(EG(in_class_exists), type, lc_name, iface_name_len+1); + efree(lc_name.v); RETURN_BOOL(((*ce)->ce_flags & ZEND_ACC_INTERFACE) > 0); } else { + zend_u_hash_del(EG(in_class_exists), type, lc_name, iface_name_len+1); + efree(lc_name.v); RETURN_FALSE; } } Index: Zend/zend_execute_API.c =================================================================== RCS file: /repository/ZendEngine2/zend_execute_API.c,v retrieving revision 1.419 diff -u -r1.419 zend_execute_API.c --- Zend/zend_execute_API.c 2 Oct 2007 08:27:19 -0000 1.419 +++ Zend/zend_execute_API.c 3 Oct 2007 06:12:26 -0000 @@ -157,6 +157,7 @@ EG(in_execution) = 0; EG(in_autoload) = NULL; + EG(in_class_exists) = NULL; EG(autoload_func) = NULL; zend_ptr_stack_init(&EG(argument_stack)); @@ -348,6 +349,10 @@ zend_hash_destroy(EG(in_autoload)); FREE_HASHTABLE(EG(in_autoload)); } + if (EG(in_class_exists)) { + zend_hash_destroy(EG(in_class_exists)); + FREE_HASHTABLE(EG(in_class_exists)); + } } zend_end_try(); EG(active) = 0; } Index: Zend/zend_globals.h =================================================================== RCS file: /repository/ZendEngine2/zend_globals.h,v retrieving revision 1.170 diff -u -r1.170 zend_globals.h --- Zend/zend_globals.h 28 Sep 2007 02:04:28 -0000 1.170 +++ Zend/zend_globals.h 3 Oct 2007 06:12:26 -0000 @@ -195,6 +195,7 @@ zend_bool in_execution; HashTable *in_autoload; + HashTable *in_class_exists; zend_function *autoload_func; zend_bool full_tables_cleanup;
-- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php