1999-04-08 02:10:10 +08:00
/*
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Zend Engine |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2006-01-05 07:53:05 +08:00
| Copyright ( c ) 1998 - 2006 Zend Technologies Ltd . ( http : //www.zend.com) |
1999-04-08 02:10:10 +08:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2001-12-11 23:16:21 +08:00
| This source file is subject to version 2.00 of the Zend license , |
2003-08-07 15:37:19 +08:00
| that is bundled with this package in the file LICENSE , and is |
2003-06-11 04:04:29 +08:00
| available through the world - wide - web at the following url : |
2001-12-11 23:16:21 +08:00
| http : //www.zend.com/license/2_00.txt. |
1999-07-16 22:58:16 +08:00
| If you did not receive a copy of the Zend license and are unable to |
| obtain it through the world - wide - web , please send a note to |
| license @ zend . com so we can mail you a copy immediately . |
1999-04-08 02:10:10 +08:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Authors : Andi Gutmans < andi @ zend . com > |
| Zeev Suraski < zeev @ zend . com > |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
*/
2003-02-01 09:49:15 +08:00
/* $Id$ */
1999-07-16 22:58:16 +08:00
1999-04-08 02:10:10 +08:00
# include <stdio.h>
# include <signal.h>
# include "zend.h"
# include "zend_compile.h"
# include "zend_execute.h"
# include "zend_API.h"
# include "zend_ptr_stack.h"
# include "zend_constants.h"
# include "zend_extensions.h"
2004-02-12 18:38:14 +08:00
# include "zend_exceptions.h"
2004-09-24 05:43:32 +08:00
# include "zend_vm.h"
2001-05-30 16:23:15 +08:00
# ifdef HAVE_SYS_TIME_H
2000-06-16 10:49:21 +08:00
# include <sys/time.h>
# endif
1999-04-08 02:10:10 +08:00
2001-07-27 18:10:39 +08:00
ZEND_API void ( * zend_execute ) ( zend_op_array * op_array TSRMLS_DC ) ;
2003-01-12 00:12:44 +08:00
ZEND_API void ( * zend_execute_internal ) ( zend_execute_data * execute_data_ptr , int return_value_used TSRMLS_DC ) ;
1999-04-08 02:10:10 +08:00
2003-08-06 15:38:56 +08:00
/* true globals */
2003-08-07 15:17:34 +08:00
ZEND_API zend_fcall_info_cache empty_fcall_info_cache = { 0 , NULL , NULL , NULL } ;
2003-08-05 18:24:40 +08:00
2003-08-06 07:50:59 +08:00
# ifdef ZEND_WIN32
# include <process.h>
2000-06-16 09:54:56 +08:00
static WNDCLASS wc ;
2000-06-16 22:27:28 +08:00
static HWND timeout_window ;
static HANDLE timeout_thread_event ;
2005-12-10 02:10:45 +08:00
static HANDLE timeout_thread_handle ;
2000-06-16 22:27:28 +08:00
static DWORD timeout_thread_id ;
static int timeout_thread_initialized = 0 ;
2000-06-16 09:54:56 +08:00
# endif
2006-03-17 16:47:41 +08:00
#if 0 &&ZEND_DEBUG
1999-04-08 02:10:10 +08:00
static void ( * original_sigsegv_handler ) ( int ) ;
static void zend_handle_sigsegv ( int dummy )
{
fflush ( stdout ) ;
1999-05-22 19:20:56 +08:00
fflush ( stderr ) ;
1999-07-09 15:35:13 +08:00
if ( original_sigsegv_handler = = zend_handle_sigsegv ) {
signal ( SIGSEGV , original_sigsegv_handler ) ;
} else {
signal ( SIGSEGV , SIG_DFL ) ;
}
1999-05-23 00:10:51 +08:00
{
2001-07-27 18:10:39 +08:00
TSRMLS_FETCH ( ) ;
1999-05-23 00:10:51 +08:00
fprintf ( stderr , " SIGSEGV caught on opcode %d on opline %d of %s() at %s:%d \n \n " ,
active_opline - > opcode ,
active_opline - EG ( active_op_array ) - > opcodes ,
2001-07-30 15:43:02 +08:00
get_active_function_name ( TSRMLS_C ) ,
2001-07-27 18:10:39 +08:00
zend_get_executed_filename ( TSRMLS_C ) ,
zend_get_executed_lineno ( TSRMLS_C ) ) ;
1999-05-23 00:10:51 +08:00
}
1999-07-09 15:35:13 +08:00
if ( original_sigsegv_handler ! = zend_handle_sigsegv ) {
original_sigsegv_handler ( dummy ) ;
}
1999-04-08 02:10:10 +08:00
}
1999-07-09 15:35:13 +08:00
# endif
1999-04-08 02:10:10 +08:00
2001-07-31 12:53:54 +08:00
static void zend_extension_activator ( zend_extension * extension TSRMLS_DC )
1999-04-08 02:10:10 +08:00
{
if ( extension - > activate ) {
extension - > activate ( ) ;
}
}
2001-07-31 12:53:54 +08:00
static void zend_extension_deactivator ( zend_extension * extension TSRMLS_DC )
1999-04-08 02:10:10 +08:00
{
if ( extension - > deactivate ) {
extension - > deactivate ( ) ;
}
}
2006-03-13 19:13:42 +08:00
static int clean_non_persistent_function ( zend_function * function TSRMLS_DC )
2000-06-05 06:09:16 +08:00
{
2006-03-13 19:13:42 +08:00
return ( function - > type = = ZEND_INTERNAL_FUNCTION ) ? ZEND_HASH_APPLY_STOP : ZEND_HASH_APPLY_REMOVE ;
2000-06-05 06:09:16 +08:00
}
2006-03-13 19:13:42 +08:00
static int clean_non_persistent_function_full ( zend_function * function TSRMLS_DC )
2000-06-05 06:09:16 +08:00
{
2006-03-14 19:24:45 +08:00
return ( function - > type ! = ZEND_INTERNAL_FUNCTION ) ;
2006-03-13 19:13:42 +08:00
}
static int clean_non_persistent_class ( zend_class_entry * * ce TSRMLS_DC )
{
return ( ( * ce ) - > type = = ZEND_INTERNAL_CLASS ) ? ZEND_HASH_APPLY_STOP : ZEND_HASH_APPLY_REMOVE ;
}
static int clean_non_persistent_class_full ( zend_class_entry * * ce TSRMLS_DC )
{
2006-03-14 19:24:45 +08:00
return ( ( * ce ) - > type ! = ZEND_INTERNAL_CLASS ) ;
2000-06-05 06:09:16 +08:00
}
2001-07-28 18:51:54 +08:00
void init_executor ( TSRMLS_D )
1999-04-08 02:10:10 +08:00
{
1999-12-19 14:39:17 +08:00
INIT_ZVAL ( EG ( uninitialized_zval ) ) ;
2004-02-11 17:42:10 +08:00
/* trick to make uninitialized_zval never be modified, passed by ref, etc. */
2002-09-10 16:37:18 +08:00
EG ( uninitialized_zval ) . refcount + + ;
1999-12-19 14:39:17 +08:00
INIT_ZVAL ( EG ( error_zval ) ) ;
1999-04-08 02:10:10 +08:00
EG ( uninitialized_zval_ptr ) = & EG ( uninitialized_zval ) ;
EG ( error_zval_ptr ) = & EG ( error_zval ) ;
zend_ptr_stack_init ( & EG ( arg_types_stack ) ) ;
1999-07-15 20:17:34 +08:00
/* destroys stack frame, therefore makes core dumps worthless */
1999-12-20 02:54:40 +08:00
#if 0 &&ZEND_DEBUG
1999-04-08 02:10:10 +08:00
original_sigsegv_handler = signal ( SIGSEGV , zend_handle_sigsegv ) ;
1999-07-15 20:17:34 +08:00
# endif
2001-09-10 08:07:32 +08:00
EG ( return_value_ptr_ptr ) = NULL ;
1999-12-19 14:39:17 +08:00
1999-04-08 02:10:10 +08:00
EG ( symtable_cache_ptr ) = EG ( symtable_cache ) - 1 ;
EG ( symtable_cache_limit ) = EG ( symtable_cache ) + SYMTABLE_CACHE_SIZE - 1 ;
EG ( no_extensions ) = 0 ;
EG ( function_table ) = CG ( function_table ) ;
EG ( class_table ) = CG ( class_table ) ;
2000-02-04 22:45:58 +08:00
EG ( in_execution ) = 0 ;
2004-03-24 22:30:59 +08:00
EG ( in_autoload ) = NULL ;
2004-08-24 04:57:40 +08:00
EG ( autoload_func ) = NULL ;
2000-02-04 22:45:58 +08:00
1999-04-13 02:29:09 +08:00
zend_ptr_stack_init ( & EG ( argument_stack ) ) ;
2004-02-11 17:42:58 +08:00
zend_ptr_stack_push ( & EG ( argument_stack ) , ( void * ) NULL ) ;
1999-04-13 02:29:09 +08:00
1999-12-22 01:14:31 +08:00
zend_hash_init ( & EG ( symbol_table ) , 50 , NULL , ZVAL_PTR_DTOR , 0 ) ;
2002-01-21 04:42:15 +08:00
{
zval * globals ;
ALLOC_ZVAL ( globals ) ;
globals - > refcount = 1 ;
globals - > is_ref = 1 ;
2006-05-10 07:53:23 +08:00
Z_TYPE_P ( globals ) = IS_ARRAY ;
Z_ARRVAL_P ( globals ) = & EG ( symbol_table ) ;
2002-01-21 04:42:15 +08:00
zend_hash_update ( & EG ( symbol_table ) , " GLOBALS " , sizeof ( " GLOBALS " ) , & globals , sizeof ( zval * ) , NULL ) ;
}
1999-04-08 02:10:10 +08:00
EG ( active_symbol_table ) = & EG ( symbol_table ) ;
2003-08-07 15:37:19 +08:00
2001-07-31 12:53:54 +08:00
zend_llist_apply ( & zend_extensions , ( llist_apply_func_t ) zend_extension_activator TSRMLS_CC ) ;
1999-05-26 06:55:13 +08:00
EG ( opline_ptr ) = NULL ;
1999-12-01 04:15:04 +08:00
2000-03-11 00:36:30 +08:00
zend_hash_init ( & EG ( included_files ) , 5 , NULL , NULL , 0 ) ;
2000-01-25 03:00:30 +08:00
EG ( ticks_count ) = 0 ;
2000-04-19 23:08:06 +08:00
EG ( user_error_handler ) = NULL ;
2000-06-16 22:27:28 +08:00
2003-02-14 20:25:09 +08:00
EG ( current_execute_data ) = NULL ;
2004-01-10 19:43:42 +08:00
zend_stack_init ( & EG ( user_error_handlers_error_reporting ) ) ;
2000-06-18 02:04:58 +08:00
zend_ptr_stack_init ( & EG ( user_error_handlers ) ) ;
2002-08-16 08:41:37 +08:00
zend_ptr_stack_init ( & EG ( user_exception_handlers ) ) ;
2000-06-18 02:04:58 +08:00
2002-05-31 20:09:19 +08:00
zend_objects_store_init ( & EG ( objects_store ) , 1024 ) ;
2001-10-26 22:13:42 +08:00
EG ( full_tables_cleanup ) = 0 ;
2000-06-16 22:27:28 +08:00
# ifdef ZEND_WIN32
EG ( timed_out ) = 0 ;
# endif
2001-08-30 23:26:30 +08:00
EG ( exception ) = NULL ;
2001-12-07 01:47:04 +08:00
2002-03-01 22:27:26 +08:00
EG ( scope ) = NULL ;
2001-12-14 00:55:04 +08:00
2002-03-01 22:27:26 +08:00
EG ( This ) = NULL ;
2006-10-12 00:11:56 +08:00
EG ( active_op_array ) = NULL ;
2006-09-11 22:30:08 +08:00
EG ( active ) = 1 ;
1999-04-08 02:10:10 +08:00
}
2006-07-12 15:54:00 +08:00
static int zval_call_destructor ( zval * * zv TSRMLS_DC )
{
if ( Z_TYPE_PP ( zv ) = = IS_OBJECT & & ( * zv ) - > refcount = = 1 ) {
return ZEND_HASH_APPLY_REMOVE ;
} else {
return ZEND_HASH_APPLY_KEEP ;
}
}
2004-07-25 15:14:49 +08:00
void shutdown_destructors ( TSRMLS_D ) {
zend_try {
2006-07-12 15:54:00 +08:00
int symbols ;
do {
symbols = zend_hash_num_elements ( & EG ( symbol_table ) ) ;
zend_hash_reverse_apply ( & EG ( symbol_table ) , ( apply_func_t ) zval_call_destructor TSRMLS_CC ) ;
} while ( symbols ! = zend_hash_num_elements ( & EG ( symbol_table ) ) ) ;
2004-07-25 15:14:49 +08:00
zend_objects_store_call_destructors ( & EG ( objects_store ) TSRMLS_CC ) ;
2004-09-17 18:13:52 +08:00
} zend_catch {
/* if we couldn't destruct cleanly, mark all objects as destructed anyway */
zend_objects_store_mark_destructed ( & EG ( objects_store ) TSRMLS_CC ) ;
2004-07-25 15:14:49 +08:00
} zend_end_try ( ) ;
}
2001-07-27 18:10:39 +08:00
void shutdown_executor ( TSRMLS_D )
1999-04-08 02:10:10 +08:00
{
2001-07-21 22:25:27 +08:00
zend_try {
2003-01-29 22:33:18 +08:00
/* Removed because this can not be safely done, e.g. in this situation:
Object 1 creates object 2
Object 3 holds reference to object 2.
Now when 1 and 2 are destroyed , 3 can still access 2 in its destructor , with
very problematic results */
/* zend_objects_store_call_destructors(&EG(objects_store) TSRMLS_CC); */
/* Moved after symbol table cleaners, because some of the cleaners can call
destructors , which would use EG ( symtable_cache_ptr ) and thus leave leaks */
/* while (EG(symtable_cache_ptr)>=EG(symtable_cache)) {
2001-07-20 22:20:34 +08:00
zend_hash_destroy ( * EG ( symtable_cache_ptr ) ) ;
efree ( * EG ( symtable_cache_ptr ) ) ;
EG ( symtable_cache_ptr ) - - ;
}
2003-01-29 22:33:18 +08:00
*/
2001-07-31 12:53:54 +08:00
zend_llist_apply ( & zend_extensions , ( llist_apply_func_t ) zend_extension_deactivator TSRMLS_CC ) ;
2003-12-17 22:25:12 +08:00
zend_hash_graceful_reverse_destroy ( & EG ( symbol_table ) ) ;
2003-07-27 21:47:58 +08:00
} zend_end_try ( ) ;
2003-07-27 23:59:37 +08:00
zend_try {
zval * zeh ;
/* remove error handlers before destroying classes and functions,
so that if handler used some class , crash would not happen */
if ( EG ( user_error_handler ) ) {
zeh = EG ( user_error_handler ) ;
EG ( user_error_handler ) = NULL ;
zval_dtor ( zeh ) ;
FREE_ZVAL ( zeh ) ;
}
if ( EG ( user_exception_handler ) ) {
zeh = EG ( user_exception_handler ) ;
EG ( user_exception_handler ) = NULL ;
zval_dtor ( zeh ) ;
FREE_ZVAL ( zeh ) ;
}
2004-01-10 19:43:42 +08:00
zend_stack_destroy ( & EG ( user_error_handlers_error_reporting ) ) ;
zend_stack_init ( & EG ( user_error_handlers_error_reporting ) ) ;
2003-07-27 23:59:37 +08:00
zend_ptr_stack_clean ( & EG ( user_error_handlers ) , ZVAL_DESTRUCTOR , 1 ) ;
zend_ptr_stack_clean ( & EG ( user_exception_handlers ) , ZVAL_DESTRUCTOR , 1 ) ;
} zend_end_try ( ) ;
2003-08-07 15:37:19 +08:00
2003-07-27 21:47:58 +08:00
zend_try {
2003-01-30 01:54:48 +08:00
/* Cleanup static data for functions and arrays.
2004-02-03 23:37:37 +08:00
We need a separate cleanup stage because of the following problem :
Suppose we destroy class X , which destroys the class ' s function table ,
and in the function table we have function foo ( ) that has static $ bar .
Now if an object of class X is assigned to $ bar , its destructor will be
called and will fail since X ' s function table is in mid - destruction .
2003-01-30 01:54:48 +08:00
So we want first of all to clean up all data and then move to tables destruction .
Note that only run - time accessed data need to be cleaned up , pre - defined data can
not contain objects and thus are not probelmatic */
2006-03-13 19:13:42 +08:00
if ( EG ( full_tables_cleanup ) ) {
zend_hash_apply ( EG ( function_table ) , ( apply_func_t ) zend_cleanup_function_data_full TSRMLS_CC ) ;
} else {
zend_hash_reverse_apply ( EG ( function_table ) , ( apply_func_t ) zend_cleanup_function_data TSRMLS_CC ) ;
}
2003-01-30 08:44:56 +08:00
zend_hash_apply ( EG ( class_table ) , ( apply_func_t ) zend_cleanup_class_data TSRMLS_CC ) ;
2003-03-02 23:24:04 +08:00
zend_ptr_stack_destroy ( & EG ( argument_stack ) ) ;
2001-07-20 22:20:34 +08:00
/* Destroy all op arrays */
2001-10-26 22:13:42 +08:00
if ( EG ( full_tables_cleanup ) ) {
2006-03-13 19:13:42 +08:00
zend_hash_apply ( EG ( function_table ) , ( apply_func_t ) clean_non_persistent_function_full TSRMLS_CC ) ;
zend_hash_apply ( EG ( class_table ) , ( apply_func_t ) clean_non_persistent_class_full TSRMLS_CC ) ;
2001-10-23 09:23:36 +08:00
} else {
2006-03-13 19:13:42 +08:00
zend_hash_reverse_apply ( EG ( function_table ) , ( apply_func_t ) clean_non_persistent_function TSRMLS_CC ) ;
zend_hash_reverse_apply ( EG ( class_table ) , ( apply_func_t ) clean_non_persistent_class TSRMLS_CC ) ;
2001-10-23 09:23:36 +08:00
}
2003-01-29 22:33:18 +08:00
while ( EG ( symtable_cache_ptr ) > = EG ( symtable_cache ) ) {
zend_hash_destroy ( * EG ( symtable_cache_ptr ) ) ;
2003-10-14 22:36:23 +08:00
FREE_HASHTABLE ( * EG ( symtable_cache_ptr ) ) ;
2003-01-29 22:33:18 +08:00
EG ( symtable_cache_ptr ) - - ;
}
2004-02-04 17:56:20 +08:00
zend_objects_store_free_object_storage ( & EG ( objects_store ) TSRMLS_CC ) ;
2001-07-21 22:25:27 +08:00
} zend_end_try ( ) ;
2000-06-05 06:09:16 +08:00
2002-09-16 09:36:48 +08:00
zend_try {
clean_non_persistent_constants ( TSRMLS_C ) ;
} zend_end_try ( ) ;
2001-07-21 22:25:27 +08:00
zend_try {
2006-03-17 16:47:41 +08:00
#if 0 &&ZEND_DEBUG
1999-07-09 15:35:13 +08:00
signal ( SIGSEGV , original_sigsegv_handler ) ;
# endif
2000-02-01 19:41:15 +08:00
2001-07-20 22:20:34 +08:00
zend_hash_destroy ( & EG ( included_files ) ) ;
2000-04-19 23:08:06 +08:00
2003-08-04 19:02:53 +08:00
zend_ptr_stack_destroy ( & EG ( arg_types_stack ) ) ;
2004-01-10 19:43:42 +08:00
zend_stack_destroy ( & EG ( user_error_handlers_error_reporting ) ) ;
2001-07-20 22:20:34 +08:00
zend_ptr_stack_destroy ( & EG ( user_error_handlers ) ) ;
2002-08-16 08:41:37 +08:00
zend_ptr_stack_destroy ( & EG ( user_exception_handlers ) ) ;
2002-05-31 20:09:19 +08:00
zend_objects_store_destroy ( & EG ( objects_store ) ) ;
2004-03-24 22:30:59 +08:00
if ( EG ( in_autoload ) ) {
zend_hash_destroy ( EG ( in_autoload ) ) ;
2004-03-25 16:14:33 +08:00
FREE_HASHTABLE ( EG ( in_autoload ) ) ;
2004-03-24 22:30:59 +08:00
}
2001-07-21 22:25:27 +08:00
} zend_end_try ( ) ;
2006-09-11 22:30:08 +08:00
EG ( active ) = 0 ;
1999-04-08 02:10:10 +08:00
}
2004-03-16 18:14:57 +08:00
/* return class name and "::" or "". */
ZEND_API char * get_active_class_name ( char * * space TSRMLS_DC )
{
if ( ! zend_is_executing ( TSRMLS_C ) ) {
if ( space ) {
* space = " " ;
}
return " " ;
}
switch ( EG ( function_state_ptr ) - > function - > type ) {
case ZEND_USER_FUNCTION :
case ZEND_INTERNAL_FUNCTION :
{
zend_class_entry * ce = EG ( function_state_ptr ) - > function - > common . scope ;
if ( space ) {
* space = ce ? " :: " : " " ;
}
return ce ? ce - > name : " " ;
}
default :
if ( space ) {
* space = " " ;
}
return " " ;
}
}
2001-07-30 15:43:02 +08:00
ZEND_API char * get_active_function_name ( TSRMLS_D )
1999-04-08 02:10:10 +08:00
{
2002-04-21 04:14:14 +08:00
if ( ! zend_is_executing ( TSRMLS_C ) ) {
return NULL ;
}
2002-11-30 19:20:25 +08:00
switch ( EG ( function_state_ptr ) - > function - > type ) {
1999-04-08 02:10:10 +08:00
case ZEND_USER_FUNCTION : {
char * function_name = ( ( zend_op_array * ) EG ( function_state_ptr ) - > function ) - > function_name ;
2003-08-07 15:37:19 +08:00
1999-04-08 02:10:10 +08:00
if ( function_name ) {
return function_name ;
} else {
return " main " ;
}
}
break ;
case ZEND_INTERNAL_FUNCTION :
return ( ( zend_internal_function * ) EG ( function_state_ptr ) - > function ) - > function_name ;
break ;
default :
return NULL ;
}
}
2001-07-27 18:10:39 +08:00
ZEND_API char * zend_get_executed_filename ( TSRMLS_D )
1999-04-08 02:10:10 +08:00
{
2000-08-10 03:22:35 +08:00
if ( EG ( active_op_array ) ) {
return EG ( active_op_array ) - > filename ;
1999-05-26 06:55:13 +08:00
} else {
return " [no active file] " ;
}
1999-04-08 02:10:10 +08:00
}
2001-07-27 18:10:39 +08:00
ZEND_API uint zend_get_executed_lineno ( TSRMLS_D )
1999-04-08 02:10:10 +08:00
{
1999-05-26 06:55:13 +08:00
if ( EG ( opline_ptr ) ) {
return active_opline - > lineno ;
} else {
return 0 ;
}
1999-04-08 02:10:10 +08:00
}
2001-07-30 15:43:02 +08:00
ZEND_API zend_bool zend_is_executing ( TSRMLS_D )
2000-02-04 22:45:58 +08:00
{
return EG ( in_execution ) ;
}
2000-01-18 01:33:37 +08:00
ZEND_API void _zval_ptr_dtor ( zval * * zval_ptr ZEND_FILE_LINE_DC )
1999-04-08 02:10:10 +08:00
{
# if DEBUG_ZEND>=2
printf ( " Reducing refcount for %x (%x): %d->%d \n " , * zval_ptr , zval_ptr , ( * zval_ptr ) - > refcount , ( * zval_ptr ) - > refcount - 1 ) ;
# endif
( * zval_ptr ) - > refcount - - ;
if ( ( * zval_ptr ) - > refcount = = 0 ) {
zval_dtor ( * zval_ptr ) ;
2004-01-19 07:47:10 +08:00
safe_free_zval_ptr_rel ( * zval_ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_CC ) ;
2001-08-07 11:17:33 +08:00
} else if ( ( * zval_ptr ) - > refcount = = 1 ) {
2006-06-05 21:58:52 +08:00
if ( ( * zval_ptr ) - > type = = IS_OBJECT ) {
TSRMLS_FETCH ( ) ;
if ( EG ( ze1_compatibility_mode ) ) {
return ;
}
}
2000-01-26 13:03:22 +08:00
( * zval_ptr ) - > is_ref = 0 ;
1999-04-08 02:10:10 +08:00
}
}
2003-08-07 15:37:19 +08:00
1999-04-08 02:10:10 +08:00
2003-08-25 01:32:47 +08:00
ZEND_API void _zval_internal_ptr_dtor ( zval * * zval_ptr ZEND_FILE_LINE_DC )
{
# if DEBUG_ZEND>=2
printf ( " Reducing refcount for %x (%x): %d->%d \n " , * zval_ptr , zval_ptr , ( * zval_ptr ) - > refcount , ( * zval_ptr ) - > refcount - 1 ) ;
# endif
( * zval_ptr ) - > refcount - - ;
if ( ( * zval_ptr ) - > refcount = = 0 ) {
zval_internal_dtor ( * zval_ptr ) ;
free ( * zval_ptr ) ;
} else if ( ( * zval_ptr ) - > refcount = = 1 ) {
( * zval_ptr ) - > is_ref = 0 ;
}
}
1999-04-08 02:10:10 +08:00
ZEND_API int zend_is_true ( zval * op )
{
return i_zend_is_true ( op ) ;
}
2001-12-01 00:29:47 +08:00
# include "../TSRM/tsrm_strtok_r.h"
1999-04-08 02:10:10 +08:00
2006-10-19 00:35:15 +08:00
ZEND_API int zval_update_constant_ex ( zval * * pp , void * arg , zend_class_entry * scope TSRMLS_DC )
1999-04-08 02:10:10 +08:00
{
1999-11-22 02:11:10 +08:00
zval * p = * pp ;
2000-06-08 14:07:38 +08:00
zend_bool inline_change = ( zend_bool ) ( unsigned long ) arg ;
2001-07-16 19:41:06 +08:00
zval const_value ;
1999-11-22 02:11:10 +08:00
2006-05-10 07:53:23 +08:00
if ( Z_TYPE_P ( p ) = = IS_CONSTANT ) {
2000-04-27 06:10:06 +08:00
int refcount ;
2005-06-08 21:21:28 +08:00
zend_uchar is_ref ;
2000-04-27 06:10:06 +08:00
2005-06-08 21:21:28 +08:00
SEPARATE_ZVAL_IF_NOT_REF ( pp ) ;
2000-04-27 06:10:06 +08:00
p = * pp ;
refcount = p - > refcount ;
2005-06-08 21:21:28 +08:00
is_ref = p - > is_ref ;
1999-04-08 02:10:10 +08:00
2006-10-19 00:35:15 +08:00
if ( ! zend_get_constant_ex ( p - > value . str . val , p - > value . str . len , & const_value , scope TSRMLS_CC ) ) {
2003-06-15 22:46:15 +08:00
zend_error ( E_NOTICE , " Use of undefined constant %s - assumed '%s' " ,
p - > value . str . val ,
p - > value . str . val ) ;
p - > type = IS_STRING ;
if ( ! inline_change ) {
zval_copy_ctor ( p ) ;
2001-12-01 00:29:47 +08:00
}
2003-06-15 22:46:15 +08:00
} else {
2000-06-01 03:07:09 +08:00
if ( inline_change ) {
STR_FREE ( p - > value . str . val ) ;
}
2001-07-16 19:41:06 +08:00
* p = const_value ;
1999-04-08 02:10:10 +08:00
}
2003-06-15 22:46:15 +08:00
1999-08-18 06:31:45 +08:00
p - > refcount = refcount ;
2005-06-08 21:21:28 +08:00
p - > is_ref = is_ref ;
2006-05-10 07:53:23 +08:00
} else if ( Z_TYPE_P ( p ) = = IS_CONSTANT_ARRAY ) {
2003-06-10 01:02:32 +08:00
zval * * element , * new_val ;
2001-07-16 19:41:06 +08:00
char * str_index ;
2001-08-21 20:29:12 +08:00
uint str_index_len ;
ulong num_index ;
2001-07-16 19:41:06 +08:00
2005-06-08 21:21:28 +08:00
SEPARATE_ZVAL_IF_NOT_REF ( pp ) ;
2000-04-27 06:10:06 +08:00
p = * pp ;
2006-05-10 07:53:23 +08:00
Z_TYPE_P ( p ) = IS_ARRAY ;
2003-08-07 15:37:19 +08:00
2001-07-16 19:41:06 +08:00
/* First go over the array and see if there are any constant indices */
2006-05-10 07:53:23 +08:00
zend_hash_internal_pointer_reset ( Z_ARRVAL_P ( p ) ) ;
while ( zend_hash_get_current_data ( Z_ARRVAL_P ( p ) , ( void * * ) & element ) = = SUCCESS ) {
2001-07-16 19:41:06 +08:00
if ( ! ( Z_TYPE_PP ( element ) & IS_CONSTANT_INDEX ) ) {
2006-05-10 07:53:23 +08:00
zend_hash_move_forward ( Z_ARRVAL_P ( p ) ) ;
2001-07-16 19:41:06 +08:00
continue ;
}
Z_TYPE_PP ( element ) & = ~ IS_CONSTANT_INDEX ;
2006-05-10 07:53:23 +08:00
if ( zend_hash_get_current_key_ex ( Z_ARRVAL_P ( p ) , & str_index , & str_index_len , & num_index , 0 , NULL ) ! = HASH_KEY_IS_STRING ) {
zend_hash_move_forward ( Z_ARRVAL_P ( p ) ) ;
2001-07-16 19:41:06 +08:00
continue ;
}
2006-10-19 00:35:15 +08:00
if ( ! zend_get_constant_ex ( str_index , str_index_len - 1 , & const_value , scope TSRMLS_CC ) ) {
2001-07-16 19:41:06 +08:00
zend_error ( E_NOTICE , " Use of undefined constant %s - assumed '%s' " , str_index , str_index ) ;
2006-05-10 07:53:23 +08:00
zend_hash_move_forward ( Z_ARRVAL_P ( p ) ) ;
2001-07-16 19:41:06 +08:00
continue ;
}
2003-08-07 15:37:19 +08:00
2006-02-26 18:57:00 +08:00
if ( const_value . type = = IS_STRING & & const_value . value . str . len = = ( int ) str_index_len - 1 & &
2002-09-10 16:35:50 +08:00
! strncmp ( const_value . value . str . val , str_index , str_index_len ) ) {
/* constant value is the same as its name */
zval_dtor ( & const_value ) ;
zend_hash_move_forward ( p - > value . ht ) ;
continue ;
}
2003-06-10 01:02:32 +08:00
ALLOC_ZVAL ( new_val ) ;
* new_val = * * element ;
zval_copy_ctor ( new_val ) ;
new_val - > refcount = 1 ;
new_val - > is_ref = 0 ;
2003-08-07 15:37:19 +08:00
2003-06-10 01:02:32 +08:00
/* preserve this bit for inheritance */
Z_TYPE_PP ( element ) | = IS_CONSTANT_INDEX ;
2005-07-07 23:16:57 +08:00
zval_ptr_dtor ( element ) ;
* element = new_val ;
2003-08-07 15:37:19 +08:00
2006-05-10 07:53:23 +08:00
switch ( Z_TYPE ( const_value ) ) {
2005-12-05 16:56:09 +08:00
case IS_STRING :
2006-05-10 07:53:23 +08:00
zend_symtable_update_current_key ( Z_ARRVAL_P ( p ) , const_value . value . str . val , const_value . value . str . len + 1 ) ;
2001-07-16 19:41:06 +08:00
break ;
2005-02-13 00:38:47 +08:00
case IS_BOOL :
2001-07-16 19:41:06 +08:00
case IS_LONG :
2006-05-10 07:53:23 +08:00
zend_hash_update_current_key ( Z_ARRVAL_P ( p ) , HASH_KEY_IS_LONG , NULL , 0 , Z_LVAL ( const_value ) ) ;
2005-07-07 23:16:57 +08:00
break ;
case IS_DOUBLE :
2006-05-10 07:53:23 +08:00
zend_hash_update_current_key ( Z_ARRVAL_P ( p ) , HASH_KEY_IS_LONG , NULL , 0 , ( long ) Z_DVAL ( const_value ) ) ;
2005-07-07 23:16:57 +08:00
break ;
case IS_NULL :
2006-05-10 07:53:23 +08:00
zend_hash_update_current_key ( Z_ARRVAL_P ( p ) , HASH_KEY_IS_STRING , " " , 1 , 0 ) ;
2001-07-16 19:41:06 +08:00
break ;
}
2006-05-10 07:53:23 +08:00
zend_hash_move_forward ( Z_ARRVAL_P ( p ) ) ;
2002-09-10 16:35:50 +08:00
zval_dtor ( & const_value ) ;
2001-07-16 19:41:06 +08:00
}
2006-05-10 07:53:23 +08:00
zend_hash_apply_with_argument ( Z_ARRVAL_P ( p ) , ( apply_func_arg_t ) zval_update_constant , ( void * ) 1 TSRMLS_CC ) ;
zend_hash_internal_pointer_reset ( Z_ARRVAL_P ( p ) ) ;
1999-04-08 02:10:10 +08:00
}
1999-11-22 02:11:10 +08:00
return 0 ;
1999-04-08 02:10:10 +08:00
}
2006-10-19 00:35:15 +08:00
ZEND_API int zval_update_constant ( zval * * pp , void * arg TSRMLS_DC )
{
zval_update_constant_ex ( pp , arg , NULL TSRMLS_CC ) ;
}
1999-08-06 23:24:10 +08:00
ntroduce infrastructure for supplying information about arguments,
including:
- Whether or not to pass by ref (replaces the old arg_types, with arg_info)
- Argument name (for future use, maybe introspection)
- Class/Interface name (for type hints)
- If a class/interface name is available, whether to allow a null instance
Both user and builtin functions share the same data structures.
To declare a builtin function that expects its first arg to be an instance
of class 'Person', its second argument as a regular arg, and its third by
reference, use:
ZEND_BEGIN_ARG_INFO(my_func_arg_info, 0)
ZEND_ARG_OBJ_INFO(0, someone, Person, 1)
ZEND_ARG_PASS_INFO(0)
ZEND_ARG_PASS_INFO(1)
ZEND_END_ARG_INFO();
and use my_func_arg_info as the arg_info parameter to the ZEND_FE() family
of macros.
The first arg to each ZEND_ARG_*() macro is whether or not to pass by ref.
The boolean arg to ZEND_BEGIN_ARG_INFO() tells the engine whether to treat
the arguments for which there's no explicit information as pass by reference
or not.
The boolean argument to ZEND_ARG_OBJ_INFO() (4th arg) is whether or not to allownull values.
2003-08-04 01:40:44 +08:00
int call_user_function ( HashTable * function_table , zval * * object_pp , zval * function_name , zval * retval_ptr , zend_uint param_count , zval * params [ ] TSRMLS_DC )
1999-08-06 23:24:10 +08:00
{
2004-07-18 17:55:02 +08:00
zval * * * params_array ;
ntroduce infrastructure for supplying information about arguments,
including:
- Whether or not to pass by ref (replaces the old arg_types, with arg_info)
- Argument name (for future use, maybe introspection)
- Class/Interface name (for type hints)
- If a class/interface name is available, whether to allow a null instance
Both user and builtin functions share the same data structures.
To declare a builtin function that expects its first arg to be an instance
of class 'Person', its second argument as a regular arg, and its third by
reference, use:
ZEND_BEGIN_ARG_INFO(my_func_arg_info, 0)
ZEND_ARG_OBJ_INFO(0, someone, Person, 1)
ZEND_ARG_PASS_INFO(0)
ZEND_ARG_PASS_INFO(1)
ZEND_END_ARG_INFO();
and use my_func_arg_info as the arg_info parameter to the ZEND_FE() family
of macros.
The first arg to each ZEND_ARG_*() macro is whether or not to pass by ref.
The boolean arg to ZEND_BEGIN_ARG_INFO() tells the engine whether to treat
the arguments for which there's no explicit information as pass by reference
or not.
The boolean argument to ZEND_ARG_OBJ_INFO() (4th arg) is whether or not to allownull values.
2003-08-04 01:40:44 +08:00
zend_uint i ;
1999-08-06 23:24:10 +08:00
int ex_retval ;
2005-07-27 02:33:15 +08:00
zval * local_retval_ptr = NULL ;
1999-08-06 23:24:10 +08:00
2004-07-18 17:55:02 +08:00
if ( param_count ) {
params_array = ( zval * * * ) emalloc ( sizeof ( zval * * ) * param_count ) ;
for ( i = 0 ; i < param_count ; i + + ) {
params_array [ i ] = & params [ i ] ;
}
} else {
params_array = NULL ;
1999-08-06 23:24:10 +08:00
}
2001-07-30 15:43:02 +08:00
ex_retval = call_user_function_ex ( function_table , object_pp , function_name , & local_retval_ptr , param_count , params_array , 1 , NULL TSRMLS_CC ) ;
1999-12-20 02:54:40 +08:00
if ( local_retval_ptr ) {
COPY_PZVAL_TO_ZVAL ( * retval_ptr , local_retval_ptr ) ;
} else {
INIT_ZVAL ( * retval_ptr ) ;
}
2004-07-18 17:55:02 +08:00
if ( params_array ) {
efree ( params_array ) ;
}
1999-08-06 23:24:10 +08:00
return ex_retval ;
}
ntroduce infrastructure for supplying information about arguments,
including:
- Whether or not to pass by ref (replaces the old arg_types, with arg_info)
- Argument name (for future use, maybe introspection)
- Class/Interface name (for type hints)
- If a class/interface name is available, whether to allow a null instance
Both user and builtin functions share the same data structures.
To declare a builtin function that expects its first arg to be an instance
of class 'Person', its second argument as a regular arg, and its third by
reference, use:
ZEND_BEGIN_ARG_INFO(my_func_arg_info, 0)
ZEND_ARG_OBJ_INFO(0, someone, Person, 1)
ZEND_ARG_PASS_INFO(0)
ZEND_ARG_PASS_INFO(1)
ZEND_END_ARG_INFO();
and use my_func_arg_info as the arg_info parameter to the ZEND_FE() family
of macros.
The first arg to each ZEND_ARG_*() macro is whether or not to pass by ref.
The boolean arg to ZEND_BEGIN_ARG_INFO() tells the engine whether to treat
the arguments for which there's no explicit information as pass by reference
or not.
The boolean argument to ZEND_ARG_OBJ_INFO() (4th arg) is whether or not to allownull values.
2003-08-04 01:40:44 +08:00
int call_user_function_ex ( HashTable * function_table , zval * * object_pp , zval * function_name , zval * * retval_ptr_ptr , zend_uint param_count , zval * * params [ ] , int no_separation , HashTable * symbol_table TSRMLS_DC )
2003-05-21 00:44:42 +08:00
{
2003-08-05 18:24:40 +08:00
zend_fcall_info fci ;
fci . size = sizeof ( fci ) ;
fci . function_table = function_table ;
fci . object_pp = object_pp ;
fci . function_name = function_name ;
fci . retval_ptr_ptr = retval_ptr_ptr ;
fci . param_count = param_count ;
fci . params = params ;
fci . no_separation = ( zend_bool ) no_separation ;
fci . symbol_table = symbol_table ;
return zend_call_function ( & fci , NULL TSRMLS_CC ) ;
2003-05-21 00:44:42 +08:00
}
ntroduce infrastructure for supplying information about arguments,
including:
- Whether or not to pass by ref (replaces the old arg_types, with arg_info)
- Argument name (for future use, maybe introspection)
- Class/Interface name (for type hints)
- If a class/interface name is available, whether to allow a null instance
Both user and builtin functions share the same data structures.
To declare a builtin function that expects its first arg to be an instance
of class 'Person', its second argument as a regular arg, and its third by
reference, use:
ZEND_BEGIN_ARG_INFO(my_func_arg_info, 0)
ZEND_ARG_OBJ_INFO(0, someone, Person, 1)
ZEND_ARG_PASS_INFO(0)
ZEND_ARG_PASS_INFO(1)
ZEND_END_ARG_INFO();
and use my_func_arg_info as the arg_info parameter to the ZEND_FE() family
of macros.
The first arg to each ZEND_ARG_*() macro is whether or not to pass by ref.
The boolean arg to ZEND_BEGIN_ARG_INFO() tells the engine whether to treat
the arguments for which there's no explicit information as pass by reference
or not.
The boolean argument to ZEND_ARG_OBJ_INFO() (4th arg) is whether or not to allownull values.
2003-08-04 01:40:44 +08:00
2003-08-05 18:24:40 +08:00
int zend_call_function ( zend_fcall_info * fci , zend_fcall_info_cache * fci_cache TSRMLS_DC )
1999-04-08 02:10:10 +08:00
{
ntroduce infrastructure for supplying information about arguments,
including:
- Whether or not to pass by ref (replaces the old arg_types, with arg_info)
- Argument name (for future use, maybe introspection)
- Class/Interface name (for type hints)
- If a class/interface name is available, whether to allow a null instance
Both user and builtin functions share the same data structures.
To declare a builtin function that expects its first arg to be an instance
of class 'Person', its second argument as a regular arg, and its third by
reference, use:
ZEND_BEGIN_ARG_INFO(my_func_arg_info, 0)
ZEND_ARG_OBJ_INFO(0, someone, Person, 1)
ZEND_ARG_PASS_INFO(0)
ZEND_ARG_PASS_INFO(1)
ZEND_END_ARG_INFO();
and use my_func_arg_info as the arg_info parameter to the ZEND_FE() family
of macros.
The first arg to each ZEND_ARG_*() macro is whether or not to pass by ref.
The boolean arg to ZEND_BEGIN_ARG_INFO() tells the engine whether to treat
the arguments for which there's no explicit information as pass by reference
or not.
The boolean argument to ZEND_ARG_OBJ_INFO() (4th arg) is whether or not to allownull values.
2003-08-04 01:40:44 +08:00
zend_uint i ;
1999-12-20 02:54:40 +08:00
zval * * original_return_value ;
1999-04-08 02:10:10 +08:00
HashTable * calling_symbol_table ;
zend_function_state * original_function_state_ptr ;
zend_op_array * original_op_array ;
zend_op * * original_opline_ptr ;
2002-03-01 22:27:26 +08:00
zend_class_entry * current_scope ;
zend_class_entry * calling_scope = NULL ;
2006-01-23 06:14:32 +08:00
zend_class_entry * check_scope_or_static = NULL ;
2002-01-05 23:18:30 +08:00
zval * current_this ;
2002-08-23 21:50:42 +08:00
zend_execute_data execute_data ;
2003-07-03 17:18:41 +08:00
zval * method_name ;
zval * params_array ;
2003-10-25 02:42:00 +08:00
int call_via_handler = 0 ;
2005-12-17 06:15:41 +08:00
char * fname , * colon ;
int fname_len ;
2002-08-23 21:50:42 +08:00
2006-09-11 22:30:08 +08:00
if ( ! EG ( active ) ) {
return FAILURE ; /* executor is already inactive */
}
2005-03-19 22:25:42 +08:00
if ( EG ( exception ) ) {
return FAILURE ; /* we would result in an instable executor otherwise */
}
2003-08-05 18:24:40 +08:00
switch ( fci - > size ) {
case sizeof ( zend_fcall_info ) :
break ; /* nothing to do currently */
default :
zend_error ( E_ERROR , " Corrupted fcall_info provided to zend_call_function() " ) ;
break ;
}
2002-08-23 21:50:42 +08:00
/* Initialize execute_data */
2004-02-05 07:48:39 +08:00
if ( EG ( current_execute_data ) ) {
execute_data = * EG ( current_execute_data ) ;
2005-06-22 23:26:05 +08:00
EX ( op_array ) = NULL ;
EX ( opline ) = NULL ;
2006-03-03 20:06:29 +08:00
EX ( object ) = NULL ;
2004-02-05 07:48:39 +08:00
} else {
2004-02-11 21:01:39 +08:00
/* This only happens when we're called outside any execute()'s
* It shouldn ' t be strictly necessary to NULL execute_data out ,
* but it may make bugs easier to spot
*/
2004-02-05 07:48:39 +08:00
memset ( & execute_data , 0 , sizeof ( zend_execute_data ) ) ;
}
2000-01-16 06:52:24 +08:00
2004-02-11 21:01:39 +08:00
/* we may return SUCCESS, and yet retval may be uninitialized,
* if there was an exception . . .
*/
* fci - > retval_ptr_ptr = NULL ;
2003-08-05 18:24:40 +08:00
if ( ! fci_cache | | ! fci_cache - > initialized ) {
2006-05-10 07:53:23 +08:00
if ( Z_TYPE_P ( fci - > function_name ) = = IS_ARRAY ) { /* assume array($obj, $name) couple */
2003-08-05 18:24:40 +08:00
zval * * tmp_object_ptr , * * tmp_real_function_name ;
2000-06-03 11:28:08 +08:00
2006-05-10 07:53:23 +08:00
if ( zend_hash_index_find ( Z_ARRVAL_P ( fci - > function_name ) , 0 , ( void * * ) & tmp_object_ptr ) = = FAILURE ) {
2003-08-05 18:24:40 +08:00
return FAILURE ;
}
2006-05-10 07:53:23 +08:00
if ( zend_hash_index_find ( Z_ARRVAL_P ( fci - > function_name ) , 1 , ( void * * ) & tmp_real_function_name ) = = FAILURE ) {
2003-08-05 18:24:40 +08:00
return FAILURE ;
}
fci - > function_name = * tmp_real_function_name ;
SEPARATE_ZVAL_IF_NOT_REF ( tmp_object_ptr ) ;
fci - > object_pp = tmp_object_ptr ;
( * fci - > object_pp ) - > is_ref = 1 ;
2000-06-03 11:28:08 +08:00
}
2003-08-05 18:24:40 +08:00
if ( fci - > object_pp & & ! * fci - > object_pp ) {
fci - > object_pp = NULL ;
2000-06-03 11:28:08 +08:00
}
2003-08-05 18:24:40 +08:00
if ( fci - > object_pp ) {
/* TBI!! new object handlers */
if ( Z_TYPE_PP ( fci - > object_pp ) = = IS_OBJECT ) {
if ( ! IS_ZEND_STD_OBJECT ( * * fci - > object_pp ) ) {
zend_error ( E_WARNING , " Cannot use call_user_function on objects without a class entry " ) ;
return FAILURE ;
}
2002-02-07 22:08:43 +08:00
2003-08-05 18:24:40 +08:00
calling_scope = Z_OBJCE_PP ( fci - > object_pp ) ;
fci - > function_table = & calling_scope - > function_table ;
EX ( object ) = * fci - > object_pp ;
2003-08-07 15:17:34 +08:00
} else if ( Z_TYPE_PP ( fci - > object_pp ) = = IS_STRING ) {
2003-07-02 22:44:41 +08:00
zend_class_entry * * ce ;
int found = FAILURE ;
2003-11-25 02:13:29 +08:00
if ( EG ( active_op_array ) & & strcmp ( Z_STRVAL_PP ( fci - > object_pp ) , " self " ) = = 0 ) {
2004-03-15 01:52:58 +08:00
if ( ! EG ( active_op_array ) - > scope ) {
zend_error ( E_ERROR , " Cannot access self:: when no class scope is active " ) ;
}
2003-07-02 22:44:41 +08:00
ce = & ( EG ( active_op_array ) - > scope ) ;
found = ( * ce ! = NULL ? SUCCESS : FAILURE ) ;
2004-03-15 01:52:58 +08:00
fci - > object_pp = EG ( This ) ? & EG ( This ) : NULL ;
2006-03-03 20:06:29 +08:00
EX ( object ) = EG ( This ) ;
2004-03-15 01:52:58 +08:00
} else if ( strcmp ( Z_STRVAL_PP ( fci - > object_pp ) , " parent " ) = = 0 & & EG ( active_op_array ) ) {
if ( ! EG ( active_op_array ) - > scope ) {
zend_error ( E_ERROR , " Cannot access parent:: when no class scope is active " ) ;
}
if ( ! EG ( active_op_array ) - > scope - > parent ) {
zend_error ( E_ERROR , " Cannot access parent:: when current class scope has no parent " ) ;
}
2003-07-02 22:44:41 +08:00
ce = & ( EG ( active_op_array ) - > scope - > parent ) ;
found = ( * ce ! = NULL ? SUCCESS : FAILURE ) ;
2004-03-15 01:52:58 +08:00
fci - > object_pp = EG ( This ) ? & EG ( This ) : NULL ;
2006-03-03 20:06:29 +08:00
EX ( object ) = EG ( This ) ;
2003-07-02 22:44:41 +08:00
} else {
2004-03-15 02:00:40 +08:00
zend_class_entry * scope ;
2004-03-17 05:29:22 +08:00
scope = EG ( active_op_array ) ? EG ( active_op_array ) - > scope : NULL ;
2004-03-15 01:52:58 +08:00
2003-11-25 02:13:29 +08:00
found = zend_lookup_class ( Z_STRVAL_PP ( fci - > object_pp ) , Z_STRLEN_PP ( fci - > object_pp ) , & ce TSRMLS_CC ) ;
2004-03-15 01:52:58 +08:00
if ( found = = FAILURE ) {
zend_error ( E_ERROR , " Class '%s' not found " , Z_STRVAL_PP ( fci - > object_pp ) ) ;
}
2006-05-10 07:53:23 +08:00
if ( scope & & EG ( This ) & &
2004-03-17 02:04:25 +08:00
instanceof_function ( Z_OBJCE_P ( EG ( This ) ) , scope TSRMLS_CC ) & &
instanceof_function ( scope , * ce TSRMLS_CC ) ) {
2004-03-16 22:39:07 +08:00
fci - > object_pp = & EG ( This ) ;
2006-03-03 20:06:29 +08:00
EX ( object ) = EG ( This ) ;
2004-03-16 22:39:07 +08:00
} else {
fci - > object_pp = NULL ;
2004-03-15 01:52:58 +08:00
}
2003-07-02 22:44:41 +08:00
}
if ( found = = FAILURE )
return FAILURE ;
2003-08-05 18:24:40 +08:00
fci - > function_table = & ( * ce ) - > function_table ;
2003-07-02 22:44:41 +08:00
calling_scope = * ce ;
2005-02-02 18:36:02 +08:00
} else {
zend_error ( E_NOTICE , " Non-callable array passed to zend_call_function() " ) ;
return FAILURE ;
2003-07-02 22:44:41 +08:00
}
2003-08-05 18:24:40 +08:00
if ( fci - > function_table = = NULL ) {
2003-07-02 22:44:41 +08:00
return FAILURE ;
}
}
2003-08-05 18:24:40 +08:00
if ( fci - > function_name - > type ! = IS_STRING ) {
1999-04-08 02:10:10 +08:00
return FAILURE ;
2003-05-21 00:44:42 +08:00
}
2000-06-03 11:28:08 +08:00
2005-12-17 06:15:41 +08:00
fname = Z_STRVAL_P ( fci - > function_name ) ;
fname_len = Z_STRLEN_P ( fci - > function_name ) ;
if ( calling_scope & & ( colon = strstr ( fname , " :: " ) ) ! = NULL ) {
int clen = colon - fname ;
int mlen = fname_len - clen - 2 ;
2006-01-19 05:06:47 +08:00
zend_class_entry * * pce , * ce_child = NULL ;
2005-12-17 06:15:41 +08:00
if ( zend_lookup_class ( fname , clen , & pce TSRMLS_CC ) = = SUCCESS ) {
ce_child = * pce ;
} else {
char * lcname = zend_str_tolower_dup ( fname , clen ) ;
/* caution: lcname is not '\0' terminated */
2006-01-23 06:14:32 +08:00
if ( calling_scope ) {
if ( clen = = sizeof ( " self " ) - 1 & & memcmp ( lcname , " self " , sizeof ( " self " ) - 1 ) = = 0 ) {
ce_child = EG ( active_op_array ) ? EG ( active_op_array ) - > scope : NULL ;
} else if ( clen = = sizeof ( " parent " ) - 1 & & memcmp ( lcname , " parent " , sizeof ( " parent " ) - 1 ) = = 0 & & EG ( active_op_array ) - > scope ) {
ce_child = EG ( active_op_array ) & & EG ( active_op_array ) - > scope ? EG ( scope ) - > parent : NULL ;
}
2005-12-17 06:15:41 +08:00
}
efree ( lcname ) ;
}
if ( ! ce_child ) {
zend_error ( E_ERROR , " Cannot call method %s() or method does not exist " , fname ) ;
return FAILURE ;
}
2006-01-23 06:14:32 +08:00
check_scope_or_static = calling_scope ;
2005-12-17 06:15:41 +08:00
fci - > function_table = & ce_child - > function_table ;
calling_scope = ce_child ;
fname = fname + clen + 2 ;
fname_len = mlen ;
}
2004-03-15 01:52:58 +08:00
if ( fci - > object_pp ) {
2004-03-16 22:39:07 +08:00
if ( Z_OBJ_HT_PP ( fci - > object_pp ) - > get_method = = NULL ) {
zend_error ( E_ERROR , " Object does not support method calls " ) ;
}
2004-03-15 01:52:58 +08:00
EX ( function_state ) . function =
2005-12-17 06:15:41 +08:00
Z_OBJ_HT_PP ( fci - > object_pp ) - > get_method ( fci - > object_pp , fname , fname_len TSRMLS_CC ) ;
2005-03-13 21:15:08 +08:00
if ( EX ( function_state ) . function & & calling_scope ! = EX ( function_state ) . function - > common . scope ) {
2005-12-17 06:15:41 +08:00
char * function_name_lc = zend_str_tolower_dup ( fname , fname_len ) ;
if ( zend_hash_find ( & calling_scope - > function_table , function_name_lc , fname_len + 1 , ( void * * ) & EX ( function_state ) . function ) = = FAILURE ) {
2005-03-13 21:15:08 +08:00
efree ( function_name_lc ) ;
2005-12-17 06:15:41 +08:00
zend_error ( E_ERROR , " Cannot call method %s::%s() or method does not exist " , calling_scope - > name , fname ) ;
2005-03-13 21:15:08 +08:00
}
efree ( function_name_lc ) ;
}
2004-03-15 01:52:58 +08:00
} else if ( calling_scope ) {
2005-12-17 06:15:41 +08:00
char * function_name_lc = zend_str_tolower_dup ( fname , fname_len ) ;
2004-03-15 01:52:58 +08:00
EX ( function_state ) . function =
2005-12-17 06:15:41 +08:00
zend_std_get_static_method ( calling_scope , function_name_lc , fname_len TSRMLS_CC ) ;
2004-03-15 01:52:58 +08:00
efree ( function_name_lc ) ;
2006-01-23 06:14:32 +08:00
if ( check_scope_or_static & & EX ( function_state ) . function
& & ! ( EX ( function_state ) . function - > common . fn_flags & ZEND_ACC_STATIC )
& & ! instanceof_function ( check_scope_or_static , calling_scope TSRMLS_CC ) ) {
zend_error ( E_ERROR , " Cannot call method %s() of class %s which is not a derived from %s " , fname , calling_scope - > name , check_scope_or_static - > name ) ;
2006-09-28 15:16:31 +08:00
return FAILURE ;
2006-01-23 06:14:32 +08:00
}
2004-03-15 01:52:58 +08:00
} else {
2005-12-17 06:15:41 +08:00
char * function_name_lc = zend_str_tolower_dup ( fname , fname_len ) ;
2001-07-16 01:48:50 +08:00
2005-12-17 06:15:41 +08:00
if ( zend_hash_find ( fci - > function_table , function_name_lc , fname_len + 1 , ( void * * ) & EX ( function_state ) . function ) = = FAILURE ) {
2004-03-15 01:52:58 +08:00
EX ( function_state ) . function = NULL ;
}
efree ( function_name_lc ) ;
}
if ( EX ( function_state ) . function = = NULL ) {
2003-07-03 17:18:41 +08:00
/* try calling __call */
2003-08-05 18:24:40 +08:00
if ( calling_scope & & calling_scope - > __call ) {
2003-07-03 17:18:41 +08:00
EX ( function_state ) . function = calling_scope - > __call ;
/* prepare params */
ALLOC_INIT_ZVAL ( method_name ) ;
2004-03-15 01:52:58 +08:00
ZVAL_STRINGL ( method_name , Z_STRVAL_P ( fci - > function_name ) , Z_STRLEN_P ( fci - > function_name ) , 0 ) ;
2003-08-07 15:37:19 +08:00
2003-07-03 17:18:41 +08:00
ALLOC_INIT_ZVAL ( params_array ) ;
array_init ( params_array ) ;
call_via_handler = 1 ;
} else {
return FAILURE ;
}
2003-05-21 00:44:42 +08:00
}
2005-09-02 15:47:28 +08:00
if ( fci_cache & &
( EX ( function_state ) . function - > type ! = ZEND_INTERNAL_FUNCTION | |
( ( zend_internal_function * ) EX ( function_state ) . function ) - > handler ! = zend_std_call_user_call ) ) {
2003-08-05 18:24:40 +08:00
fci_cache - > function_handler = EX ( function_state ) . function ;
fci_cache - > object_pp = fci - > object_pp ;
fci_cache - > calling_scope = calling_scope ;
fci_cache - > initialized = 1 ;
}
2003-05-21 00:44:42 +08:00
} else {
2003-08-05 18:24:40 +08:00
EX ( function_state ) . function = fci_cache - > function_handler ;
calling_scope = fci_cache - > calling_scope ;
fci - > object_pp = fci_cache - > object_pp ;
2006-03-03 20:06:29 +08:00
EX ( object ) = fci - > object_pp ? * fci - > object_pp : NULL ;
1999-04-08 02:10:10 +08:00
}
2006-05-10 07:53:23 +08:00
2006-02-26 02:25:45 +08:00
if ( EX ( function_state ) . function - > common . fn_flags & ( ZEND_ACC_ABSTRACT | ZEND_ACC_DEPRECATED ) ) {
if ( EX ( function_state ) . function - > common . fn_flags & ZEND_ACC_ABSTRACT ) {
2006-04-21 06:49:20 +08:00
zend_error_noreturn ( E_ERROR , " Cannot call abstract method %s::%s() " , EX ( function_state ) . function - > common . scope - > name , EX ( function_state ) . function - > common . function_name ) ;
2006-02-26 02:25:45 +08:00
}
if ( EX ( function_state ) . function - > common . fn_flags & ZEND_ACC_DEPRECATED ) {
zend_error ( E_STRICT , " Function %s%s%s() is deprecated " ,
EX ( function_state ) . function - > common . scope ? EX ( function_state ) . function - > common . scope - > name : " " ,
EX ( function_state ) . function - > common . scope ? " :: " : " " ,
EX ( function_state ) . function - > common . function_name ) ;
}
}
2003-08-07 15:37:19 +08:00
2003-08-05 18:24:40 +08:00
for ( i = 0 ; i < fci - > param_count ; i + + ) {
1999-04-08 02:10:10 +08:00
zval * param ;
ntroduce infrastructure for supplying information about arguments,
including:
- Whether or not to pass by ref (replaces the old arg_types, with arg_info)
- Argument name (for future use, maybe introspection)
- Class/Interface name (for type hints)
- If a class/interface name is available, whether to allow a null instance
Both user and builtin functions share the same data structures.
To declare a builtin function that expects its first arg to be an instance
of class 'Person', its second argument as a regular arg, and its third by
reference, use:
ZEND_BEGIN_ARG_INFO(my_func_arg_info, 0)
ZEND_ARG_OBJ_INFO(0, someone, Person, 1)
ZEND_ARG_PASS_INFO(0)
ZEND_ARG_PASS_INFO(1)
ZEND_END_ARG_INFO();
and use my_func_arg_info as the arg_info parameter to the ZEND_FE() family
of macros.
The first arg to each ZEND_ARG_*() macro is whether or not to pass by ref.
The boolean arg to ZEND_BEGIN_ARG_INFO() tells the engine whether to treat
the arguments for which there's no explicit information as pass by reference
or not.
The boolean argument to ZEND_ARG_OBJ_INFO() (4th arg) is whether or not to allownull values.
2003-08-04 01:40:44 +08:00
if ( ARG_SHOULD_BE_SENT_BY_REF ( EX ( function_state ) . function , i + 1 )
2003-08-05 18:24:40 +08:00
& & ! PZVAL_IS_REF ( * fci - > params [ i ] ) ) {
if ( ( * fci - > params [ i ] ) - > refcount > 1 ) {
1999-08-06 23:24:10 +08:00
zval * new_zval ;
2003-08-05 18:24:40 +08:00
if ( fci - > no_separation ) {
2005-05-19 02:02:50 +08:00
if ( i ) {
/* hack to clean up the stack */
zend_ptr_stack_n_push ( & EG ( argument_stack ) , 2 , ( void * ) ( long ) i , NULL ) ;
zend_ptr_stack_clear_multiple ( TSRMLS_C ) ;
}
1999-08-06 23:24:10 +08:00
return FAILURE ;
}
1999-12-27 05:21:33 +08:00
ALLOC_ZVAL ( new_zval ) ;
2003-08-05 18:24:40 +08:00
* new_zval = * * fci - > params [ i ] ;
1999-08-07 05:43:49 +08:00
zval_copy_ctor ( new_zval ) ;
1999-08-06 23:24:10 +08:00
new_zval - > refcount = 1 ;
2003-08-05 18:24:40 +08:00
( * fci - > params [ i ] ) - > refcount - - ;
* fci - > params [ i ] = new_zval ;
1999-08-06 23:24:10 +08:00
}
2003-08-05 18:24:40 +08:00
( * fci - > params [ i ] ) - > refcount + + ;
( * fci - > params [ i ] ) - > is_ref = 1 ;
param = * fci - > params [ i ] ;
} else if ( * fci - > params [ i ] ! = & EG ( uninitialized_zval ) ) {
( * fci - > params [ i ] ) - > refcount + + ;
param = * fci - > params [ i ] ;
1999-08-06 23:24:10 +08:00
} else {
1999-12-27 05:21:33 +08:00
ALLOC_ZVAL ( param ) ;
2003-08-05 18:24:40 +08:00
* param = * * ( fci - > params [ i ] ) ;
1999-08-06 23:24:10 +08:00
INIT_PZVAL ( param ) ;
}
2003-08-05 18:24:40 +08:00
if ( call_via_handler ) {
2003-07-03 17:18:41 +08:00
add_next_index_zval ( params_array , param ) ;
} else {
zend_ptr_stack_push ( & EG ( argument_stack ) , param ) ;
}
}
2003-08-05 18:24:40 +08:00
if ( call_via_handler ) {
2003-07-03 17:18:41 +08:00
zend_ptr_stack_push ( & EG ( argument_stack ) , method_name ) ;
zend_ptr_stack_push ( & EG ( argument_stack ) , params_array ) ;
2003-08-05 18:24:40 +08:00
fci - > param_count = 2 ;
1999-04-08 02:10:10 +08:00
}
2004-07-31 05:00:37 +08:00
zend_ptr_stack_2_push ( & EG ( argument_stack ) , ( void * ) ( long ) fci - > param_count , NULL ) ;
1999-04-08 02:10:10 +08:00
2003-08-07 15:37:19 +08:00
original_function_state_ptr = EG ( function_state_ptr ) ;
2002-08-23 21:50:42 +08:00
EG ( function_state_ptr ) = & EX ( function_state ) ;
2001-02-03 15:21:35 +08:00
2002-03-01 22:27:26 +08:00
current_scope = EG ( scope ) ;
EG ( scope ) = calling_scope ;
2001-12-27 04:17:34 +08:00
2002-03-01 22:27:26 +08:00
current_this = EG ( This ) ;
2002-01-05 23:18:30 +08:00
2003-08-05 18:24:40 +08:00
if ( fci - > object_pp ) {
2004-03-16 22:59:06 +08:00
if ( ( EX ( function_state ) . function - > common . fn_flags & ZEND_ACC_STATIC ) ) {
EG ( This ) = NULL ;
} else {
2004-03-16 22:49:52 +08:00
EG ( This ) = * fci - > object_pp ;
2002-01-15 00:55:23 +08:00
2004-03-16 22:49:52 +08:00
if ( ! PZVAL_IS_REF ( EG ( This ) ) ) {
EG ( This ) - > refcount + + ; /* For $this pointer */
} else {
zval * this_ptr ;
2002-01-05 23:18:30 +08:00
2004-03-16 22:49:52 +08:00
ALLOC_ZVAL ( this_ptr ) ;
* this_ptr = * EG ( This ) ;
INIT_PZVAL ( this_ptr ) ;
zval_copy_ctor ( this_ptr ) ;
EG ( This ) = this_ptr ;
}
2002-01-05 23:18:30 +08:00
}
2002-01-15 00:55:23 +08:00
} else {
2002-03-01 22:27:26 +08:00
EG ( This ) = NULL ;
2004-01-24 04:58:23 +08:00
if ( calling_scope & & ! ( EX ( function_state ) . function - > common . fn_flags & ZEND_ACC_STATIC ) ) {
int severity ;
2004-01-25 00:59:24 +08:00
if ( EX ( function_state ) . function - > common . fn_flags & ZEND_ACC_ALLOW_STATIC ) {
2004-01-24 04:58:23 +08:00
severity = E_STRICT ;
2004-01-25 00:59:24 +08:00
} else {
severity = E_ERROR ;
2004-01-24 04:58:23 +08:00
}
2005-01-29 04:24:20 +08:00
zend_error ( severity , " Non-static method %s::%s() cannot be called statically " , calling_scope - > name , EX ( function_state ) . function - > common . function_name ) ;
2004-01-24 04:58:23 +08:00
}
2002-01-05 23:18:30 +08:00
}
2002-08-23 21:50:42 +08:00
EX ( prev_execute_data ) = EG ( current_execute_data ) ;
EG ( current_execute_data ) = & execute_data ;
2002-01-05 23:18:30 +08:00
2002-08-23 21:50:42 +08:00
if ( EX ( function_state ) . function - > type = = ZEND_USER_FUNCTION ) {
1999-04-14 03:28:03 +08:00
calling_symbol_table = EG ( active_symbol_table ) ;
2003-09-12 01:04:26 +08:00
EG ( scope ) = EX ( function_state ) . function - > common . scope ;
2003-08-05 18:24:40 +08:00
if ( fci - > symbol_table ) {
EG ( active_symbol_table ) = fci - > symbol_table ;
2000-06-18 00:50:38 +08:00
} else {
ALLOC_HASHTABLE ( EG ( active_symbol_table ) ) ;
zend_hash_init ( EG ( active_symbol_table ) , 0 , NULL , ZVAL_PTR_DTOR , 0 ) ;
}
2002-01-05 23:18:30 +08:00
1999-12-20 02:54:40 +08:00
original_return_value = EG ( return_value_ptr_ptr ) ;
1999-04-08 02:10:10 +08:00
original_op_array = EG ( active_op_array ) ;
2003-08-05 18:24:40 +08:00
EG ( return_value_ptr_ptr ) = fci - > retval_ptr_ptr ;
2002-08-23 21:50:42 +08:00
EG ( active_op_array ) = ( zend_op_array * ) EX ( function_state ) . function ;
1999-12-20 02:54:40 +08:00
original_opline_ptr = EG ( opline_ptr ) ;
2001-07-27 18:10:39 +08:00
zend_execute ( EG ( active_op_array ) TSRMLS_CC ) ;
2003-08-05 18:24:40 +08:00
if ( ! fci - > symbol_table ) {
2000-06-18 00:50:38 +08:00
zend_hash_destroy ( EG ( active_symbol_table ) ) ;
FREE_HASHTABLE ( EG ( active_symbol_table ) ) ;
}
1999-04-14 03:28:03 +08:00
EG ( active_symbol_table ) = calling_symbol_table ;
1999-04-08 02:10:10 +08:00
EG ( active_op_array ) = original_op_array ;
1999-12-20 02:54:40 +08:00
EG ( return_value_ptr_ptr ) = original_return_value ;
1999-04-08 02:10:10 +08:00
EG ( opline_ptr ) = original_opline_ptr ;
} else {
2003-08-05 18:24:40 +08:00
ALLOC_INIT_ZVAL ( * fci - > retval_ptr_ptr ) ;
2003-09-12 01:06:53 +08:00
if ( EX ( function_state ) . function - > common . scope ) {
2003-09-12 01:04:26 +08:00
EG ( scope ) = EX ( function_state ) . function - > common . scope ;
}
2005-06-16 22:56:13 +08:00
( ( zend_internal_function * ) EX ( function_state ) . function ) - > handler ( fci - > param_count , * fci - > retval_ptr_ptr , EX ( function_state ) . function - > common . return_reference ? fci - > retval_ptr_ptr : NULL , ( fci - > object_pp ? * fci - > object_pp : NULL ) , 1 TSRMLS_CC ) ;
2003-08-05 18:24:40 +08:00
INIT_PZVAL ( * fci - > retval_ptr_ptr ) ;
1999-04-08 02:10:10 +08:00
}
2001-07-27 18:10:39 +08:00
zend_ptr_stack_clear_multiple ( TSRMLS_C ) ;
2003-08-05 18:24:40 +08:00
if ( call_via_handler ) {
2003-07-03 17:18:41 +08:00
zval_ptr_dtor ( & method_name ) ;
zval_ptr_dtor ( & params_array ) ;
}
1999-04-08 02:10:10 +08:00
EG ( function_state_ptr ) = original_function_state_ptr ;
2002-03-01 22:27:26 +08:00
if ( EG ( This ) ) {
zval_ptr_dtor ( & EG ( This ) ) ;
2002-01-05 23:18:30 +08:00
}
2002-03-01 22:27:26 +08:00
EG ( scope ) = current_scope ;
EG ( This ) = current_this ;
2003-08-05 18:24:40 +08:00
EG ( current_execute_data ) = EX ( prev_execute_data ) ;
2004-02-03 20:17:09 +08:00
if ( EG ( exception ) ) {
zend_throw_exception_internal ( NULL TSRMLS_CC ) ;
}
2003-08-05 18:24:40 +08:00
return SUCCESS ;
1999-04-08 02:10:10 +08:00
}
2003-08-05 18:24:40 +08:00
2005-09-09 14:48:49 +08:00
ZEND_API int zend_lookup_class_ex ( char * name , int name_length , int use_autoload , zend_class_entry * * * ce TSRMLS_DC )
2002-06-17 02:25:05 +08:00
{
2002-06-26 23:13:14 +08:00
zval * * args [ 1 ] ;
2003-11-07 19:47:50 +08:00
zval autoload_function ;
2005-05-26 22:28:24 +08:00
zval * class_name_ptr ;
2005-12-20 19:25:34 +08:00
zval * retval_ptr = NULL ;
2002-06-26 23:13:14 +08:00
int retval ;
2003-11-25 02:13:29 +08:00
char * lc_name ;
2003-12-12 02:18:52 +08:00
zval * exception ;
2004-03-24 22:30:59 +08:00
char dummy = 1 ;
2004-08-24 04:57:40 +08:00
zend_fcall_info fcall_info ;
zend_fcall_info_cache fcall_cache ;
2004-11-17 20:06:27 +08:00
if ( name = = NULL ) {
return FAILURE ;
}
2004-03-24 22:30:59 +08:00
2003-11-25 02:13:29 +08:00
lc_name = do_alloca ( name_length + 1 ) ;
2003-12-15 15:17:27 +08:00
zend_str_tolower_copy ( lc_name , name , name_length ) ;
2003-11-25 02:13:29 +08:00
if ( zend_hash_find ( EG ( class_table ) , lc_name , name_length + 1 , ( void * * ) ce ) = = SUCCESS ) {
free_alloca ( lc_name ) ;
2002-06-26 23:13:14 +08:00
return SUCCESS ;
}
2004-03-28 17:37:30 +08:00
/* The compiler is not-reentrant. Make sure we __autoload() only during run-time
* ( doesn ' t impact fuctionality of __autoload ( )
*/
2005-09-09 14:48:49 +08:00
if ( ! use_autoload | | zend_is_compiling ( TSRMLS_C ) ) {
2004-03-28 17:37:30 +08:00
free_alloca ( lc_name ) ;
return FAILURE ;
}
2004-03-24 22:30:59 +08:00
if ( EG ( in_autoload ) = = NULL ) {
2004-03-25 16:14:33 +08:00
ALLOC_HASHTABLE ( EG ( in_autoload ) ) ;
2004-03-24 22:30:59 +08:00
zend_hash_init ( EG ( in_autoload ) , 0 , NULL , NULL , 0 ) ;
}
if ( zend_hash_add ( EG ( in_autoload ) , lc_name , name_length + 1 , ( void * * ) & dummy , sizeof ( char ) , NULL ) = = FAILURE ) {
2003-12-23 18:45:10 +08:00
free_alloca ( lc_name ) ;
return FAILURE ;
}
2004-08-02 16:27:57 +08:00
ZVAL_STRINGL ( & autoload_function , ZEND_AUTOLOAD_FUNC_NAME , sizeof ( ZEND_AUTOLOAD_FUNC_NAME ) - 1 , 0 ) ;
2002-06-17 02:25:05 +08:00
2005-05-26 22:28:24 +08:00
ALLOC_ZVAL ( class_name_ptr ) ;
2003-11-07 19:47:50 +08:00
INIT_PZVAL ( class_name_ptr ) ;
2005-05-26 22:28:24 +08:00
ZVAL_STRINGL ( class_name_ptr , name , name_length , 1 ) ;
2003-11-07 19:47:50 +08:00
args [ 0 ] = & class_name_ptr ;
2006-05-10 07:53:23 +08:00
2004-08-24 04:57:40 +08:00
fcall_info . size = sizeof ( fcall_info ) ;
fcall_info . function_table = EG ( function_table ) ;
fcall_info . function_name = & autoload_function ;
fcall_info . symbol_table = NULL ;
fcall_info . retval_ptr_ptr = & retval_ptr ;
fcall_info . param_count = 1 ;
fcall_info . params = args ;
fcall_info . object_pp = NULL ;
fcall_info . no_separation = 1 ;
fcall_cache . initialized = EG ( autoload_func ) ? 1 : 0 ;
fcall_cache . function_handler = EG ( autoload_func ) ;
fcall_cache . calling_scope = NULL ;
fcall_cache . object_pp = NULL ;
2002-06-26 23:13:14 +08:00
2003-12-12 02:18:52 +08:00
exception = EG ( exception ) ;
EG ( exception ) = NULL ;
2004-08-24 04:57:40 +08:00
retval = zend_call_function ( & fcall_info , & fcall_cache TSRMLS_CC ) ;
EG ( autoload_func ) = fcall_cache . function_handler ;
2003-08-07 15:37:19 +08:00
2005-05-26 22:28:24 +08:00
zval_ptr_dtor ( & class_name_ptr ) ;
2004-03-24 22:30:59 +08:00
zend_hash_del ( EG ( in_autoload ) , lc_name , name_length + 1 ) ;
2003-12-23 18:45:10 +08:00
2002-06-26 23:13:14 +08:00
if ( retval = = FAILURE ) {
2003-12-12 02:18:52 +08:00
EG ( exception ) = exception ;
2003-11-25 02:13:29 +08:00
free_alloca ( lc_name ) ;
2002-06-26 23:13:14 +08:00
return FAILURE ;
}
2005-02-14 07:04:49 +08:00
if ( EG ( exception ) & & exception ) {
2003-11-25 02:13:29 +08:00
free_alloca ( lc_name ) ;
2004-08-02 16:27:57 +08:00
zend_error ( E_ERROR , " Function %s(%s) threw an exception of type '%s' " , ZEND_AUTOLOAD_FUNC_NAME , name , Z_OBJCE_P ( EG ( exception ) ) - > name ) ;
2003-12-12 02:18:52 +08:00
return FAILURE ;
2002-08-14 00:46:40 +08:00
}
2005-02-14 07:04:49 +08:00
if ( ! EG ( exception ) ) {
EG ( exception ) = exception ;
2005-12-20 19:25:34 +08:00
}
if ( retval_ptr ) {
2005-02-14 07:04:49 +08:00
zval_ptr_dtor ( & retval_ptr ) ;
}
2002-06-26 23:13:14 +08:00
2003-11-25 02:13:29 +08:00
retval = zend_hash_find ( EG ( class_table ) , lc_name , name_length + 1 , ( void * * ) ce ) ;
free_alloca ( lc_name ) ;
return retval ;
2002-06-26 23:13:14 +08:00
}
1999-04-08 02:10:10 +08:00
2005-09-09 14:48:49 +08:00
ZEND_API int zend_lookup_class ( char * name , int name_length , zend_class_entry * * * ce TSRMLS_DC )
{
return zend_lookup_class_ex ( name , name_length , 1 , ce TSRMLS_CC ) ;
}
2001-07-28 18:51:54 +08:00
ZEND_API int zend_eval_string ( char * str , zval * retval_ptr , char * string_name TSRMLS_DC )
1999-04-08 02:10:10 +08:00
{
zval pv ;
zend_op_array * new_op_array ;
zend_op_array * original_active_op_array = EG ( active_op_array ) ;
zend_function_state * original_function_state_ptr = EG ( function_state_ptr ) ;
2002-04-24 02:06:54 +08:00
zend_uchar original_handle_op_arrays ;
2000-05-07 02:49:46 +08:00
int retval ;
1999-04-08 02:10:10 +08:00
1999-12-20 02:54:40 +08:00
if ( retval_ptr ) {
1999-04-08 02:10:10 +08:00
pv . value . str . len = strlen ( str ) + sizeof ( " return ; " ) - 1 ;
pv . value . str . val = emalloc ( pv . value . str . len + 1 ) ;
strcpy ( pv . value . str . val , " return " ) ;
strcat ( pv . value . str . val , str ) ;
strcat ( pv . value . str . val , " ; " ) ;
} else {
pv . value . str . len = strlen ( str ) ;
pv . value . str . val = estrndup ( str , pv . value . str . len ) ;
}
pv . type = IS_STRING ;
/*printf("Evaluating '%s'\n", pv.value.str.val);*/
original_handle_op_arrays = CG ( handle_op_arrays ) ;
CG ( handle_op_arrays ) = 0 ;
2006-06-13 20:57:48 +08:00
new_op_array = zend_compile_string ( & pv , string_name TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
CG ( handle_op_arrays ) = original_handle_op_arrays ;
if ( new_op_array ) {
1999-12-20 02:54:40 +08:00
zval * local_retval_ptr = NULL ;
zval * * original_return_value_ptr_ptr = EG ( return_value_ptr_ptr ) ;
1999-04-08 02:10:10 +08:00
zend_op * * original_opline_ptr = EG ( opline_ptr ) ;
2003-08-07 15:37:19 +08:00
1999-12-20 02:54:40 +08:00
EG ( return_value_ptr_ptr ) = & local_retval_ptr ;
1999-04-08 02:10:10 +08:00
EG ( active_op_array ) = new_op_array ;
EG ( no_extensions ) = 1 ;
1999-12-20 02:54:40 +08:00
2001-07-27 18:10:39 +08:00
zend_execute ( new_op_array TSRMLS_CC ) ;
1999-12-20 02:54:40 +08:00
if ( local_retval_ptr ) {
if ( retval_ptr ) {
COPY_PZVAL_TO_ZVAL ( * retval_ptr , local_retval_ptr ) ;
} else {
zval_ptr_dtor ( & local_retval_ptr ) ;
}
} else {
if ( retval_ptr ) {
INIT_ZVAL ( * retval_ptr ) ;
}
}
1999-04-08 02:10:10 +08:00
EG ( no_extensions ) = 0 ;
EG ( opline_ptr ) = original_opline_ptr ;
EG ( active_op_array ) = original_active_op_array ;
EG ( function_state_ptr ) = original_function_state_ptr ;
2003-03-26 15:44:11 +08:00
destroy_op_array ( new_op_array TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
efree ( new_op_array ) ;
1999-12-20 02:54:40 +08:00
EG ( return_value_ptr_ptr ) = original_return_value_ptr_ptr ;
2000-05-07 02:49:46 +08:00
retval = SUCCESS ;
1999-04-08 02:10:10 +08:00
} else {
2000-05-07 02:49:46 +08:00
retval = FAILURE ;
1999-04-08 02:10:10 +08:00
}
zval_dtor ( & pv ) ;
2000-05-07 02:49:46 +08:00
return retval ;
1999-04-08 02:10:10 +08:00
}
2003-08-24 21:10:03 +08:00
ZEND_API int zend_eval_string_ex ( char * str , zval * retval_ptr , char * string_name , int handle_exceptions TSRMLS_DC )
{
int result ;
result = zend_eval_string ( str , retval_ptr , string_name TSRMLS_CC ) ;
if ( handle_exceptions & & EG ( exception ) ) {
zend_exception_error ( EG ( exception ) TSRMLS_CC ) ;
result = FAILURE ;
}
return result ;
}
2001-07-28 18:51:54 +08:00
void execute_new_code ( TSRMLS_D )
1999-04-08 02:10:10 +08:00
{
2004-03-16 22:59:06 +08:00
zend_op * opline , * end ;
2001-07-15 22:08:58 +08:00
zend_op * ret_opline ;
2001-09-10 08:07:32 +08:00
zval * local_retval = NULL ;
1999-04-08 02:10:10 +08:00
2001-07-15 22:08:58 +08:00
if ( ! CG ( interactive )
1999-04-27 19:00:59 +08:00
| | CG ( active_op_array ) - > backpatch_count > 0
| | CG ( active_op_array ) - > function_name
| | CG ( active_op_array ) - > type ! = ZEND_USER_FUNCTION ) {
1999-04-08 02:10:10 +08:00
return ;
}
2001-04-30 12:50:34 +08:00
2001-07-28 18:51:54 +08:00
ret_opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
2001-07-15 22:08:58 +08:00
ret_opline - > opcode = ZEND_RETURN ;
ret_opline - > op1 . op_type = IS_CONST ;
INIT_ZVAL ( ret_opline - > op1 . u . constant ) ;
SET_UNUSED ( ret_opline - > op2 ) ;
2005-11-24 19:33:11 +08:00
zend_do_handle_exception ( TSRMLS_C ) ;
2001-07-15 22:08:58 +08:00
if ( ! CG ( active_op_array ) - > start_op ) {
CG ( active_op_array ) - > start_op = CG ( active_op_array ) - > opcodes ;
}
2003-08-07 15:37:19 +08:00
2001-07-15 22:08:58 +08:00
opline = CG ( active_op_array ) - > start_op ;
2001-05-06 23:00:58 +08:00
end = CG ( active_op_array ) - > opcodes + CG ( active_op_array ) - > last ;
2001-04-30 12:50:34 +08:00
2004-03-16 22:59:06 +08:00
while ( opline < end ) {
if ( opline - > op1 . op_type = = IS_CONST ) {
opline - > op1 . u . constant . is_ref = 1 ;
opline - > op1 . u . constant . refcount = 2 ; /* Make sure is_ref won't be reset */
}
if ( opline - > op2 . op_type = = IS_CONST ) {
opline - > op2 . u . constant . is_ref = 1 ;
opline - > op2 . u . constant . refcount = 2 ;
}
2005-03-26 10:43:02 +08:00
switch ( opline - > opcode ) {
case ZEND_JMP :
opline - > op1 . u . jmp_addr = & CG ( active_op_array ) - > opcodes [ opline - > op1 . u . opline_num ] ;
break ;
case ZEND_JMPZ :
case ZEND_JMPNZ :
case ZEND_JMPZ_EX :
case ZEND_JMPNZ_EX :
opline - > op2 . u . jmp_addr = & CG ( active_op_array ) - > opcodes [ opline - > op2 . u . opline_num ] ;
break ;
}
2004-09-24 05:43:32 +08:00
ZEND_VM_SET_OPCODE_HANDLER ( opline ) ;
2003-06-15 19:44:30 +08:00
opline + + ;
2004-03-16 22:59:06 +08:00
}
2001-04-30 12:50:34 +08:00
2001-09-10 08:07:32 +08:00
EG ( return_value_ptr_ptr ) = & local_retval ;
1999-04-08 02:10:10 +08:00
EG ( active_op_array ) = CG ( active_op_array ) ;
2001-07-27 18:10:39 +08:00
zend_execute ( CG ( active_op_array ) TSRMLS_CC ) ;
2001-09-10 08:07:32 +08:00
if ( local_retval ) {
zval_ptr_dtor ( & local_retval ) ;
}
2005-11-24 19:33:11 +08:00
if ( EG ( exception ) ) {
zend_exception_error ( EG ( exception ) TSRMLS_CC ) ;
}
CG ( active_op_array ) - > last - = 2 ; /* get rid of that ZEND_RETURN and ZEND_HANDLE_EXCEPTION */
2001-07-15 22:08:58 +08:00
CG ( active_op_array ) - > start_op = CG ( active_op_array ) - > opcodes + CG ( active_op_array ) - > last ;
1999-04-08 02:10:10 +08:00
}
1999-04-13 02:29:09 +08:00
2000-07-02 23:39:54 +08:00
ZEND_API void zend_timeout ( int dummy )
2000-06-16 09:54:56 +08:00
{
2001-07-27 18:10:39 +08:00
TSRMLS_FETCH ( ) ;
2000-06-16 09:54:56 +08:00
2002-09-19 23:58:01 +08:00
if ( zend_on_timeout ) {
zend_on_timeout ( EG ( timeout_seconds ) TSRMLS_CC ) ;
}
2003-01-23 13:15:42 +08:00
zend_error ( E_ERROR , " Maximum execution time of %d second%s exceeded " ,
EG ( timeout_seconds ) , EG ( timeout_seconds ) = = 1 ? " " : " s " ) ;
2000-06-16 09:54:56 +08:00
}
2000-06-16 10:49:21 +08:00
# ifdef ZEND_WIN32
2003-08-07 15:37:19 +08:00
static LRESULT CALLBACK zend_timeout_WndProc ( HWND hWnd , UINT message , WPARAM wParam , LPARAM lParam )
2000-06-16 09:54:56 +08:00
{
switch ( message ) {
case WM_DESTROY :
PostQuitMessage ( 0 ) ;
2000-06-16 22:27:28 +08:00
break ;
case WM_REGISTER_ZEND_TIMEOUT :
/* wParam is the thread id pointer, lParam is the timeout amount in seconds */
2000-06-26 23:17:36 +08:00
if ( lParam = = 0 ) {
KillTimer ( timeout_window , wParam ) ;
} else {
2004-05-19 04:14:54 +08:00
# ifdef ZTS
2004-01-28 17:07:02 +08:00
void * * * tsrm_ls ;
2004-05-19 04:14:54 +08:00
# endif
2000-06-26 23:17:36 +08:00
SetTimer ( timeout_window , wParam , lParam * 1000 , NULL ) ;
2004-05-19 04:14:54 +08:00
# ifdef ZTS
2004-01-28 17:07:02 +08:00
tsrm_ls = ts_resource_ex ( 0 , & wParam ) ;
if ( ! tsrm_ls ) {
/* shouldn't normally happen */
break ;
}
2004-05-19 04:14:54 +08:00
# endif
2004-01-28 17:07:02 +08:00
EG ( timed_out ) = 0 ;
2000-06-26 23:17:36 +08:00
}
2000-06-16 22:27:28 +08:00
break ;
case WM_UNREGISTER_ZEND_TIMEOUT :
/* wParam is the thread id pointer */
KillTimer ( timeout_window , wParam ) ;
break ;
case WM_TIMER : {
# ifdef ZTS
2001-07-28 18:51:54 +08:00
void * * * tsrm_ls ;
2000-06-16 22:27:28 +08:00
2001-07-28 18:51:54 +08:00
tsrm_ls = ts_resource_ex ( 0 , & wParam ) ;
if ( ! tsrm_ls ) {
2000-06-16 22:27:28 +08:00
/* Thread died before receiving its timeout? */
break ;
}
# endif
KillTimer ( timeout_window , wParam ) ;
2001-07-28 18:51:54 +08:00
EG ( timed_out ) = 1 ;
2000-06-16 22:27:28 +08:00
}
break ;
2000-06-16 09:54:56 +08:00
default :
2001-08-11 23:56:40 +08:00
return DefWindowProc ( hWnd , message , wParam , lParam ) ;
2000-06-16 09:54:56 +08:00
}
2000-06-16 22:27:28 +08:00
return 0 ;
2000-06-16 09:54:56 +08:00
}
2000-06-16 22:27:28 +08:00
static unsigned __stdcall timeout_thread_proc ( void * pArgs )
2000-06-16 09:54:56 +08:00
{
2000-06-16 22:27:28 +08:00
MSG message ;
2000-06-16 09:54:56 +08:00
wc . style = 0 ;
wc . lpfnWndProc = zend_timeout_WndProc ;
wc . cbClsExtra = 0 ;
wc . cbWndExtra = 0 ;
wc . hInstance = NULL ;
wc . hIcon = NULL ;
wc . hCursor = NULL ;
wc . hbrBackground = ( HBRUSH ) ( COLOR_BACKGROUND + 5 ) ;
wc . lpszMenuName = NULL ;
wc . lpszClassName = " Zend Timeout Window " ;
2001-04-28 02:51:56 +08:00
if ( ! RegisterClass ( & wc ) ) {
2000-06-16 22:27:28 +08:00
return - 1 ;
}
timeout_window = CreateWindow ( wc . lpszClassName , wc . lpszClassName , 0 , CW_USEDEFAULT , CW_USEDEFAULT , CW_USEDEFAULT , CW_USEDEFAULT , NULL , NULL , NULL , NULL ) ;
SetEvent ( timeout_thread_event ) ;
while ( GetMessage ( & message , NULL , 0 , 0 ) ) {
SendMessage ( timeout_window , message . message , message . wParam , message . lParam ) ;
if ( message . message = = WM_QUIT ) {
break ;
}
2000-06-16 09:54:56 +08:00
}
2000-06-16 22:27:28 +08:00
DestroyWindow ( timeout_window ) ;
UnregisterClass ( wc . lpszClassName , NULL ) ;
2005-12-23 00:46:15 +08:00
SetEvent ( timeout_thread_handle ) ;
2000-06-16 22:27:28 +08:00
return 0 ;
2000-06-16 09:54:56 +08:00
}
2000-06-16 22:27:28 +08:00
void zend_init_timeout_thread ( )
2000-06-16 09:54:56 +08:00
{
2000-06-16 22:27:28 +08:00
timeout_thread_event = CreateEvent ( NULL , FALSE , FALSE , NULL ) ;
2005-12-23 00:46:15 +08:00
timeout_thread_handle = CreateEvent ( NULL , FALSE , FALSE , NULL ) ;
_beginthreadex ( NULL , 0 , timeout_thread_proc , NULL , 0 , & timeout_thread_id ) ;
2000-06-16 22:27:28 +08:00
WaitForSingleObject ( timeout_thread_event , INFINITE ) ;
2000-06-16 09:54:56 +08:00
}
2000-06-16 22:27:28 +08:00
void zend_shutdown_timeout_thread ( )
2000-06-16 09:54:56 +08:00
{
2000-06-16 22:27:28 +08:00
if ( ! timeout_thread_initialized ) {
return ;
}
PostThreadMessage ( timeout_thread_id , WM_QUIT , 0 , 0 ) ;
2005-12-10 02:10:45 +08:00
/* Wait for thread termination */
WaitForSingleObject ( timeout_thread_handle , 5000 ) ;
CloseHandle ( timeout_thread_handle ) ;
2006-05-25 15:46:25 +08:00
timeout_thread_initialized = 0 ;
2000-06-16 09:54:56 +08:00
}
2000-06-16 22:27:28 +08:00
2000-06-16 09:54:56 +08:00
# endif
/* This one doesn't exists on QNX */
# ifndef SIGPROF
# define SIGPROF 27
# endif
void zend_set_timeout ( long seconds )
{
2001-07-27 18:10:39 +08:00
TSRMLS_FETCH ( ) ;
2000-06-16 09:54:56 +08:00
EG ( timeout_seconds ) = seconds ;
# ifdef ZEND_WIN32
2000-06-16 22:27:28 +08:00
if ( timeout_thread_initialized = = 0 & & InterlockedIncrement ( & timeout_thread_initialized ) = = 1 ) {
/* We start up this process-wide thread here and not in zend_startup(), because if Zend
* is initialized inside a DllMain ( ) , you ' re not supposed to start threads from it .
*/
zend_init_timeout_thread ( ) ;
}
PostThreadMessage ( timeout_thread_id , WM_REGISTER_ZEND_TIMEOUT , ( WPARAM ) GetCurrentThreadId ( ) , ( LPARAM ) seconds ) ;
2000-06-16 09:54:56 +08:00
# else
# ifdef HAVE_SETITIMER
2000-06-16 10:49:21 +08:00
{
struct itimerval t_r ; /* timeout requested */
2000-07-04 00:53:39 +08:00
sigset_t sigset ;
2000-06-16 09:54:56 +08:00
2000-06-16 10:49:21 +08:00
t_r . it_value . tv_sec = seconds ;
t_r . it_value . tv_usec = t_r . it_interval . tv_sec = t_r . it_interval . tv_usec = 0 ;
2000-06-16 09:54:56 +08:00
2005-07-12 14:52:59 +08:00
# ifdef __CYGWIN__
setitimer ( ITIMER_REAL , & t_r , NULL ) ;
signal ( SIGALRM , zend_timeout ) ;
sigemptyset ( & sigset ) ;
sigaddset ( & sigset , SIGALRM ) ;
# else
2000-06-16 10:49:21 +08:00
setitimer ( ITIMER_PROF , & t_r , NULL ) ;
signal ( SIGPROF , zend_timeout ) ;
2000-07-04 00:53:39 +08:00
sigemptyset ( & sigset ) ;
sigaddset ( & sigset , SIGPROF ) ;
2005-07-12 14:52:59 +08:00
# endif
2001-08-11 23:56:40 +08:00
sigprocmask ( SIG_UNBLOCK , & sigset , NULL ) ;
2000-06-16 10:49:21 +08:00
}
2000-06-16 09:54:56 +08:00
# endif
# endif
}
2001-07-30 15:43:02 +08:00
void zend_unset_timeout ( TSRMLS_D )
2000-06-16 09:54:56 +08:00
{
# ifdef ZEND_WIN32
2000-06-16 22:27:28 +08:00
PostThreadMessage ( timeout_thread_id , WM_UNREGISTER_ZEND_TIMEOUT , ( WPARAM ) GetCurrentThreadId ( ) , ( LPARAM ) 0 ) ;
2000-06-16 09:54:56 +08:00
# else
# ifdef HAVE_SETITIMER
2000-06-16 10:49:21 +08:00
{
struct itimerval no_timeout ;
2000-06-16 09:54:56 +08:00
2000-06-16 10:49:21 +08:00
no_timeout . it_value . tv_sec = no_timeout . it_value . tv_usec = no_timeout . it_interval . tv_sec = no_timeout . it_interval . tv_usec = 0 ;
2000-06-16 09:54:56 +08:00
2005-08-03 01:01:17 +08:00
# ifdef __CYGWIN__
setitimer ( ITIMER_REAL , & no_timeout , NULL ) ;
# else
2000-06-16 10:49:21 +08:00
setitimer ( ITIMER_PROF , & no_timeout , NULL ) ;
2005-08-03 01:01:17 +08:00
# endif
2000-06-16 10:49:21 +08:00
}
2000-06-16 09:54:56 +08:00
# endif
# endif
}
2003-02-01 09:49:15 +08:00
2003-08-03 16:21:08 +08:00
zend_class_entry * zend_fetch_class ( char * class_name , uint class_name_len , int fetch_type TSRMLS_DC )
{
zend_class_entry * * pce ;
2005-09-09 14:48:49 +08:00
int use_autoload = ( fetch_type & ZEND_FETCH_CLASS_NO_AUTOLOAD ) = = 0 ;
2003-08-03 16:21:08 +08:00
2005-09-09 14:48:49 +08:00
fetch_type = fetch_type & ~ ZEND_FETCH_CLASS_NO_AUTOLOAD ;
2003-08-03 16:21:08 +08:00
check_fetch_type :
switch ( fetch_type ) {
case ZEND_FETCH_CLASS_SELF :
if ( ! EG ( scope ) ) {
zend_error ( E_ERROR , " Cannot access self:: when no class scope is active " ) ;
}
return EG ( scope ) ;
case ZEND_FETCH_CLASS_PARENT :
if ( ! EG ( scope ) ) {
zend_error ( E_ERROR , " Cannot access parent:: when no class scope is active " ) ;
}
if ( ! EG ( scope ) - > parent ) {
zend_error ( E_ERROR , " Cannot access parent:: when current class scope has no parent " ) ;
}
return EG ( scope ) - > parent ;
case ZEND_FETCH_CLASS_AUTO : {
fetch_type = zend_get_class_fetch_type ( class_name , class_name_len ) ;
if ( fetch_type ! = ZEND_FETCH_CLASS_DEFAULT ) {
goto check_fetch_type ;
}
}
break ;
}
2005-09-09 14:48:49 +08:00
if ( zend_lookup_class_ex ( class_name , class_name_len , use_autoload , & pce TSRMLS_CC ) = = FAILURE ) {
if ( use_autoload ) {
if ( fetch_type = = ZEND_FETCH_CLASS_INTERFACE ) {
zend_error ( E_ERROR , " Interface '%s' not found " , class_name ) ;
} else {
zend_error ( E_ERROR , " Class '%s' not found " , class_name ) ;
}
2005-06-24 16:45:17 +08:00
}
2005-09-09 14:48:49 +08:00
return NULL ;
2003-08-03 16:21:08 +08:00
}
return * pce ;
}
2004-02-03 20:17:09 +08:00
2004-02-05 00:30:15 +08:00
# define MAX_ABSTRACT_INFO_CNT 3
# define MAX_ABSTRACT_INFO_FMT "%s%s%s%s"
# define DISPLAY_ABSTRACT_FN(idx) \
ai . afn [ idx ] ? ZEND_FN_SCOPE_NAME ( ai . afn [ idx ] ) : " " , \
ai . afn [ idx ] ? " :: " : " " , \
ai . afn [ idx ] ? ai . afn [ idx ] - > common . function_name : " " , \
2005-07-22 00:52:32 +08:00
ai . afn [ idx ] & & ai . afn [ idx + 1 ] ? " , " : ( ai . afn [ idx ] & & ai . cnt > MAX_ABSTRACT_INFO_CNT ? " , ... " : " " )
2004-02-05 00:30:15 +08:00
typedef struct _zend_abstract_info {
zend_function * afn [ MAX_ABSTRACT_INFO_CNT + 1 ] ;
int cnt ;
} zend_abstract_info ;
static int zend_verify_abstract_class_function ( zend_function * fn , zend_abstract_info * ai TSRMLS_DC )
{
if ( fn - > common . fn_flags & ZEND_ACC_ABSTRACT ) {
if ( ai - > cnt < MAX_ABSTRACT_INFO_CNT ) {
ai - > afn [ ai - > cnt ] = fn ;
}
ai - > cnt + + ;
}
return 0 ;
}
void zend_verify_abstract_class ( zend_class_entry * ce TSRMLS_DC )
{
zend_abstract_info ai ;
2004-03-10 00:38:37 +08:00
if ( ( ce - > ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS ) & & ! ( ce - > ce_flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS ) ) {
2004-02-05 00:30:15 +08:00
memset ( & ai , 0 , sizeof ( ai ) ) ;
zend_hash_apply_with_argument ( & ce - > function_table , ( apply_func_arg_t ) zend_verify_abstract_class_function , & ai TSRMLS_CC ) ;
2004-03-09 00:52:59 +08:00
2006-05-10 07:53:23 +08:00
if ( ai . cnt ) {
zend_error ( E_ERROR , " Class %s contains %d abstract method%s and must therefore be declared abstract or implement the remaining methods ( " MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT " ) " ,
ce - > name , ai . cnt ,
2005-05-02 23:55:05 +08:00
ai . cnt > 1 ? " s " : " " ,
2004-03-09 00:52:59 +08:00
DISPLAY_ABSTRACT_FN ( 0 ) ,
DISPLAY_ABSTRACT_FN ( 1 ) ,
DISPLAY_ABSTRACT_FN ( 2 )
) ;
}
2004-02-05 00:30:15 +08:00
}
}
2005-07-04 18:01:10 +08:00
ZEND_API void zend_reset_all_cv ( HashTable * symbol_table TSRMLS_DC )
{
zend_execute_data * ex ;
int i ;
for ( ex = EG ( current_execute_data ) ; ex ; ex = ex - > prev_execute_data ) {
2005-10-28 03:25:52 +08:00
if ( ex - > op_array & & ex - > symbol_table = = symbol_table ) {
2005-07-04 18:01:10 +08:00
for ( i = 0 ; i < ex - > op_array - > last_var ; i + + ) {
ex - > CVs [ i ] = NULL ;
}
}
}
}
2004-10-05 04:17:06 +08:00
ZEND_API int zend_delete_global_variable ( char * name , int name_len TSRMLS_DC )
2004-10-05 03:54:35 +08:00
{
zend_execute_data * ex ;
2004-10-05 14:53:39 +08:00
ulong hash_value = zend_inline_hash_func ( name , name_len + 1 ) ;
2004-10-05 03:54:35 +08:00
2004-10-05 14:53:39 +08:00
if ( zend_hash_quick_exists ( & EG ( symbol_table ) , name , name_len + 1 , hash_value ) ) {
2004-10-05 03:54:35 +08:00
for ( ex = EG ( current_execute_data ) ; ex ; ex = ex - > prev_execute_data ) {
2005-10-28 03:25:52 +08:00
if ( ex - > op_array & & ex - > symbol_table = = & EG ( symbol_table ) ) {
2004-10-05 03:54:35 +08:00
int i ;
for ( i = 0 ; i < ex - > op_array - > last_var ; i + + ) {
2004-10-05 14:53:39 +08:00
if ( ex - > op_array - > vars [ i ] . hash_value = = hash_value & &
ex - > op_array - > vars [ i ] . name_len = = name_len & &
2004-10-05 03:54:35 +08:00
! memcmp ( ex - > op_array - > vars [ i ] . name , name , name_len ) ) {
ex - > CVs [ i ] = NULL ;
break ;
}
}
}
}
2004-10-05 14:53:39 +08:00
return zend_hash_del ( & EG ( symbol_table ) , name , name_len + 1 ) ;
2004-10-05 03:54:35 +08:00
}
return FAILURE ;
}
2004-02-05 00:30:15 +08:00
2003-02-01 09:49:15 +08:00
/*
* Local variables :
* tab - width : 4
* c - basic - offset : 4
* indent - tabs - mode : t
* End :
*/