Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:32585 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 97935 invoked by uid 1010); 3 Oct 2007 06:18:32 -0000 Delivered-To: ezmlm-scan-internals@lists.php.net Delivered-To: ezmlm-internals@lists.php.net Received: (qmail 97920 invoked from network); 3 Oct 2007 06:18:32 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 3 Oct 2007 06:18:32 -0000 Authentication-Results: pb1.pair.com smtp.mail=greg@chiaraquartet.net; spf=permerror; sender-id=unknown Authentication-Results: pb1.pair.com header.from=greg@chiaraquartet.net; sender-id=unknown Received-SPF: error (pb1.pair.com: domain chiaraquartet.net from 38.99.98.18 cause and error) X-PHP-List-Original-Sender: greg@chiaraquartet.net X-Host-Fingerprint: 38.99.98.18 beast.bluga.net Linux 2.6 Received: from [38.99.98.18] ([38.99.98.18:35982] helo=mail.bluga.net) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id A4/D5-58646-63433074 for ; Wed, 03 Oct 2007 02:18:31 -0400 Received: from mail.bluga.net (localhost.localdomain [127.0.0.1]) by mail.bluga.net (Postfix) with ESMTP id 254A5C0DD6C for ; Tue, 2 Oct 2007 23:18:28 -0700 (MST) Received: from [192.168.0.106] (CPE-76-84-5-144.neb.res.rr.com [76.84.5.144]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mail.bluga.net (Postfix) with ESMTP id 25211C0DD6B for ; Tue, 2 Oct 2007 23:18:27 -0700 (MST) Message-ID: <470334FE.7050808@chiaraquartet.net> Date: Wed, 03 Oct 2007 01:21:50 -0500 User-Agent: Thunderbird 1.5.0.13 (X11/20070824) MIME-Version: 1.0 To: internals Mailing List X-Enigmail-Version: 0.94.2.0 Content-Type: multipart/mixed; boundary="------------000502060008010108050806" X-Virus-Scanned: ClamAV using ClamSMTP Subject: [PATCH] in_class_exists() for detecting __autoload() called by class_exists() and interface_exists() From: greg@chiaraquartet.net (Gregory Beaver) --------------000502060008010108050806 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit 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: 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 --------------000502060008010108050806 Content-Type: text/plain; name="in_class_exists.patch.txt" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="in_class_exists.patch.txt" 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; --------------000502060008010108050806 Content-Type: text/plain; name="php6_in_class_exists.patch.txt" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="php6_in_class_exists.patch.txt" 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; --------------000502060008010108050806--