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