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

Reply via email to