1999-04-08 02:10:10 +08:00
/*
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Zend Engine |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2014-01-03 11:08:10 +08:00
| Copyright ( c ) 1998 - 2014 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"
2014-02-10 14:04:30 +08:00
# include "zend_stack.h"
1999-04-08 02:10:10 +08:00
# include "zend_constants.h"
# include "zend_extensions.h"
2004-02-12 18:38:14 +08:00
# include "zend_exceptions.h"
2008-07-14 17:49:03 +08:00
# include "zend_closures.h"
2012-07-20 06:49:50 +08:00
# include "zend_generators.h"
2004-09-24 05:43:32 +08:00
# include "zend_vm.h"
2009-03-18 18:41:39 +08:00
# include "zend_float.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
2012-11-30 17:39:23 +08:00
ZEND_API void ( * zend_execute_ex ) ( zend_execute_data * execute_data TSRMLS_DC ) ;
2014-07-07 19:50:44 +08:00
ZEND_API void ( * zend_execute_internal ) ( zend_execute_data * execute_data , zval * return_value TSRMLS_DC ) ;
1999-04-08 02:10:10 +08:00
2003-08-06 15:38:56 +08:00
/* true globals */
2014-09-15 17:28:24 +08:00
ZEND_API const zend_fcall_info empty_fcall_info = { 0 , NULL , { { 0 } , { { 0 } } , { 0 } } , NULL , NULL , NULL , NULL , 0 , 0 } ;
2014-03-28 06:11:22 +08:00
ZEND_API const zend_fcall_info_cache empty_fcall_info_cache = { 0 , NULL , 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 ) ;
2007-11-03 03:40:39 +08:00
static void zend_handle_sigsegv ( int dummy ) /* { { { */
1999-04-08 02:10:10 +08:00
{
fflush ( stdout ) ;
1999-05-22 19:20:56 +08:00
fflush ( stderr ) ;
2007-11-03 03:40:39 +08:00
if ( original_sigsegv_handler = = zend_handle_sigsegv ) {
1999-07-09 15:35:13 +08:00
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 ) ) ;
2010-01-25 22:47:19 +08:00
/* See http://support.microsoft.com/kb/190351 */
# ifdef PHP_WIN32
fflush ( stderr ) ;
# endif
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
}
2007-11-03 03:40:39 +08:00
/* }}} */
1999-07-09 15:35:13 +08:00
# endif
1999-04-08 02:10:10 +08:00
2007-11-03 03:40:39 +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 ( ) ;
}
}
2007-11-03 03:40:39 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2007-11-03 03:40:39 +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 ( ) ;
}
}
2007-11-03 03:40:39 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-03-18 18:52:54 +08:00
static int clean_non_persistent_function ( zval * zv TSRMLS_DC ) /* { { { */
2000-06-05 06:09:16 +08:00
{
2014-03-18 18:52:54 +08:00
zend_function * function = Z_PTR_P ( zv ) ;
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
}
2007-11-03 03:40:39 +08:00
/* }}} */
2000-06-05 06:09:16 +08:00
2014-09-02 06:08:02 +08:00
ZEND_API int clean_non_persistent_function_full ( zval * zv TSRMLS_DC ) /* { { { */
2000-06-05 06:09:16 +08:00
{
2014-03-18 18:52:54 +08:00
zend_function * function = Z_PTR_P ( zv ) ;
2012-01-17 16:09:13 +08:00
return ( function - > type = = ZEND_INTERNAL_FUNCTION ) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_REMOVE ;
2006-03-13 19:13:42 +08:00
}
2007-11-03 03:40:39 +08:00
/* }}} */
2006-03-13 19:13:42 +08:00
2014-03-18 18:52:54 +08:00
static int clean_non_persistent_class ( zval * zv TSRMLS_DC ) /* { { { */
2006-03-13 19:13:42 +08:00
{
2014-03-18 18:52:54 +08:00
zend_class_entry * ce = Z_PTR_P ( zv ) ;
return ( ce - > type = = ZEND_INTERNAL_CLASS ) ? ZEND_HASH_APPLY_STOP : ZEND_HASH_APPLY_REMOVE ;
2006-03-13 19:13:42 +08:00
}
2007-11-03 03:40:39 +08:00
/* }}} */
2006-03-13 19:13:42 +08:00
2014-09-02 06:08:02 +08:00
ZEND_API int clean_non_persistent_class_full ( zval * zv TSRMLS_DC ) /* { { { */
2006-03-13 19:13:42 +08:00
{
2014-03-18 18:52:54 +08:00
zend_class_entry * ce = Z_PTR_P ( zv ) ;
return ( ce - > type = = ZEND_INTERNAL_CLASS ) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_REMOVE ;
2000-06-05 06:09:16 +08:00
}
2007-11-03 03:40:39 +08:00
/* }}} */
2000-06-05 06:09:16 +08:00
2007-11-03 03:40:39 +08:00
void init_executor ( TSRMLS_D ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2009-03-18 18:18:10 +08:00
zend_init_fpu ( TSRMLS_C ) ;
2014-02-10 14:04:30 +08:00
ZVAL_NULL ( & EG ( uninitialized_zval ) ) ;
2007-11-03 03:40:39 +08:00
/* trick to make uninitialized_zval never be modified, passed by ref, etc. */
2014-02-10 14:04:30 +08:00
ZVAL_NULL ( & EG ( error_zval ) ) ;
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
1999-12-19 14:39:17 +08:00
2007-11-03 03:40:39 +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 ;
1999-04-08 02:10:10 +08:00
EG ( function_table ) = CG ( function_table ) ;
EG ( class_table ) = CG ( class_table ) ;
2004-03-24 22:30:59 +08:00
EG ( in_autoload ) = NULL ;
2004-08-24 04:57:40 +08:00
EG ( autoload_func ) = NULL ;
2008-10-03 03:54:03 +08:00
EG ( error_handling ) = EH_NORMAL ;
2000-02-04 22:45:58 +08:00
2008-01-24 17:41:39 +08:00
zend_vm_stack_init ( TSRMLS_C ) ;
1999-04-13 02:29:09 +08:00
2014-04-21 22:25:34 +08:00
zend_hash_init ( & EG ( symbol_table ) . ht , 64 , NULL , ZVAL_PTR_DTOR , 0 ) ;
2014-06-10 01:29:20 +08:00
GC_REFCOUNT ( & EG ( symbol_table ) ) = 1 ;
2014-05-29 03:32:52 +08:00
GC_TYPE_INFO ( & EG ( symbol_table ) ) = IS_ARRAY ;
2014-07-04 22:03:45 +08:00
EG ( valid_symbol_table ) = 1 ;
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-12-01 04:15:04 +08:00
2014-04-21 22:25:34 +08:00
zend_hash_init ( & EG ( included_files ) , 8 , NULL , NULL , 0 ) ;
2000-01-25 03:00:30 +08:00
EG ( ticks_count ) = 0 ;
2000-04-19 23:08:06 +08:00
2014-02-10 14:04:30 +08:00
ZVAL_UNDEF ( & EG ( user_error_handler ) ) ;
2000-06-16 22:27:28 +08:00
2003-02-14 20:25:09 +08:00
EG ( current_execute_data ) = NULL ;
2014-05-01 02:28:02 +08:00
zend_stack_init ( & EG ( user_error_handlers_error_reporting ) , sizeof ( int ) ) ;
zend_stack_init ( & EG ( user_error_handlers ) , sizeof ( zval ) ) ;
zend_stack_init ( & EG ( user_exception_handlers ) , sizeof ( zval ) ) ;
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 ;
2008-08-14 18:24:52 +08:00
EG ( prev_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
2006-09-11 22:30:08 +08:00
EG ( active ) = 1 ;
1999-04-08 02:10:10 +08:00
}
2007-11-03 03:40:39 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-02-10 14:04:30 +08:00
static int zval_call_destructor ( zval * zv TSRMLS_DC ) /* { { { */
2006-07-12 15:54:00 +08:00
{
2014-03-26 22:07:31 +08:00
if ( Z_TYPE_P ( zv ) = = IS_INDIRECT ) {
zv = Z_INDIRECT_P ( zv ) ;
}
2014-02-10 14:04:30 +08:00
if ( Z_TYPE_P ( zv ) = = IS_OBJECT & & Z_REFCOUNT_P ( zv ) = = 1 ) {
2006-07-12 15:54:00 +08:00
return ZEND_HASH_APPLY_REMOVE ;
} else {
return ZEND_HASH_APPLY_KEEP ;
}
}
2007-11-03 03:40:39 +08:00
/* }}} */
2006-07-12 15:54:00 +08:00
2014-03-28 06:11:22 +08:00
static void zend_unclean_zval_ptr_dtor ( zval * zv ) /* { { { */
2014-03-26 22:07:31 +08:00
{
TSRMLS_FETCH ( ) ;
if ( Z_TYPE_P ( zv ) = = IS_INDIRECT ) {
zv = Z_INDIRECT_P ( zv ) ;
}
i_zval_ptr_dtor ( zv ZEND_FILE_LINE_CC TSRMLS_CC ) ;
}
/* }}} */
2007-11-03 03:40:39 +08:00
void shutdown_destructors ( TSRMLS_D ) /* { { { */
{
2014-03-26 22:07:31 +08:00
if ( CG ( unclean_shutdown ) ) {
EG ( symbol_table ) . ht . pDestructor = zend_unclean_zval_ptr_dtor ;
}
2004-07-25 15:14:49 +08:00
zend_try {
2006-07-12 15:54:00 +08:00
int symbols ;
do {
2014-02-10 14:04:30 +08:00
symbols = zend_hash_num_elements ( & EG ( symbol_table ) . ht ) ;
zend_hash_reverse_apply ( & EG ( symbol_table ) . ht , ( apply_func_t ) zval_call_destructor TSRMLS_CC ) ;
} while ( symbols ! = zend_hash_num_elements ( & EG ( symbol_table ) . ht ) ) ;
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 ( ) ;
}
2007-11-03 03:40:39 +08:00
/* }}} */
2004-07-25 15:14:49 +08:00
2007-11-03 03:40:39 +08:00
void shutdown_executor ( TSRMLS_D ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2014-04-21 17:55:25 +08:00
zend_function * func ;
zend_class_entry * ce ;
2001-07-21 22:25:27 +08:00
zend_try {
2007-11-03 03:40:39 +08:00
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 ) ;
2014-03-26 22:07:31 +08:00
if ( CG ( unclean_shutdown ) ) {
EG ( symbol_table ) . ht . pDestructor = zend_unclean_zval_ptr_dtor ;
}
2014-02-10 14:04:30 +08:00
zend_hash_graceful_reverse_destroy ( & EG ( symbol_table ) . ht ) ;
2003-07-27 21:47:58 +08:00
} zend_end_try ( ) ;
2014-07-04 22:03:45 +08:00
EG ( valid_symbol_table ) = 0 ;
2003-07-27 23:59:37 +08:00
zend_try {
zval * zeh ;
/* remove error handlers before destroying classes and functions,
2007-11-03 03:40:39 +08:00
* so that if handler used some class , crash would not happen */
2014-02-10 14:04:30 +08:00
if ( Z_TYPE ( EG ( user_error_handler ) ) ! = IS_UNDEF ) {
zeh = & EG ( user_error_handler ) ;
zval_ptr_dtor ( zeh ) ;
2014-02-24 17:26:09 +08:00
ZVAL_UNDEF ( & EG ( user_error_handler ) ) ;
2003-07-27 23:59:37 +08:00
}
2014-02-10 14:04:30 +08:00
if ( Z_TYPE ( EG ( user_exception_handler ) ) ! = IS_UNDEF ) {
zeh = & EG ( user_exception_handler ) ;
zval_ptr_dtor ( zeh ) ;
2014-02-24 17:26:09 +08:00
ZVAL_UNDEF ( & EG ( user_exception_handler ) ) ;
2003-07-27 23:59:37 +08:00
}
2014-05-01 02:28:02 +08:00
zend_stack_clean ( & EG ( user_error_handlers_error_reporting ) , NULL , 1 ) ;
2014-02-10 14:04:30 +08:00
zend_stack_clean ( & EG ( user_error_handlers ) , ( void ( * ) ( void * ) ) ZVAL_DESTRUCTOR , 1 ) ;
zend_stack_clean ( & EG ( user_exception_handlers ) , ( void ( * ) ( void * ) ) ZVAL_DESTRUCTOR , 1 ) ;
2003-07-27 23:59:37 +08:00
} 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.
2007-11-03 03:40:39 +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 .
* 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 ) ) {
2014-04-21 17:55:25 +08:00
ZEND_HASH_FOREACH_PTR ( EG ( function_table ) , func ) {
if ( func - > type = = ZEND_USER_FUNCTION ) {
zend_cleanup_op_array_data ( ( zend_op_array * ) func ) ;
}
} ZEND_HASH_FOREACH_END ( ) ;
ZEND_HASH_REVERSE_FOREACH_PTR ( EG ( class_table ) , ce ) {
if ( ce - > type = = ZEND_USER_CLASS ) {
zend_cleanup_user_class_data ( ce TSRMLS_CC ) ;
} else {
zend_cleanup_internal_class_data ( ce TSRMLS_CC ) ;
}
} ZEND_HASH_FOREACH_END ( ) ;
2006-03-13 19:13:42 +08:00
} else {
2014-04-21 17:55:25 +08:00
ZEND_HASH_REVERSE_FOREACH_PTR ( EG ( function_table ) , func ) {
if ( func - > type ! = ZEND_USER_FUNCTION ) {
break ;
}
zend_cleanup_op_array_data ( ( zend_op_array * ) func ) ;
} ZEND_HASH_FOREACH_END ( ) ;
ZEND_HASH_REVERSE_FOREACH_PTR ( EG ( class_table ) , ce ) {
if ( ce - > type ! = ZEND_USER_CLASS ) {
break ;
}
zend_cleanup_user_class_data ( ce TSRMLS_CC ) ;
} ZEND_HASH_FOREACH_END ( ) ;
2010-07-06 19:40:17 +08:00
zend_cleanup_internal_classes ( TSRMLS_C ) ;
2006-03-13 19:13:42 +08:00
}
2011-04-15 20:43:20 +08:00
} zend_end_try ( ) ;
2003-03-02 23:24:04 +08:00
2014-04-11 06:22:00 +08:00
zend_try {
zend_llist_destroy ( & CG ( open_files ) ) ;
} zend_end_try ( ) ;
zend_try {
zend_close_rsrc_list ( & EG ( regular_list ) TSRMLS_CC ) ;
} zend_end_try ( ) ;
2011-04-15 20:43:20 +08:00
zend_try {
2008-08-12 01:44:15 +08:00
zend_objects_store_free_object_storage ( & EG ( objects_store ) TSRMLS_CC ) ;
2012-11-30 17:39:23 +08:00
zend_vm_stack_destroy ( TSRMLS_C ) ;
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 ) ) {
2014-03-21 17:51:18 +08:00
zend_hash_reverse_apply ( EG ( function_table ) , clean_non_persistent_function_full TSRMLS_CC ) ;
zend_hash_reverse_apply ( EG ( class_table ) , clean_non_persistent_class_full TSRMLS_CC ) ;
2001-10-23 09:23:36 +08:00
} else {
2014-03-21 17:51:18 +08:00
zend_hash_reverse_apply ( EG ( function_table ) , clean_non_persistent_function TSRMLS_CC ) ;
zend_hash_reverse_apply ( EG ( class_table ) , 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 ) ) {
2014-03-18 03:15:22 +08:00
zend_hash_destroy ( & ( * EG ( symtable_cache_ptr ) ) - > ht ) ;
2014-04-25 15:54:10 +08:00
FREE_HASHTABLE ( * EG ( symtable_cache_ptr ) ) ;
2003-01-29 22:33:18 +08:00
EG ( symtable_cache_ptr ) - - ;
}
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
2004-01-10 19:43:42 +08:00
zend_stack_destroy ( & EG ( user_error_handlers_error_reporting ) ) ;
2014-02-10 14:04:30 +08:00
zend_stack_destroy ( & EG ( user_error_handlers ) ) ;
zend_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 ( ) ;
2009-03-18 18:18:10 +08:00
zend_shutdown_fpu ( TSRMLS_C ) ;
2006-09-11 22:30:08 +08:00
EG ( active ) = 0 ;
1999-04-08 02:10:10 +08:00
}
2007-11-03 03:40:39 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2004-03-16 18:14:57 +08:00
/* return class name and "::" or "". */
2011-09-13 21:29:35 +08:00
ZEND_API const char * get_active_class_name ( const char * * space TSRMLS_DC ) /* { { { */
2004-03-16 18:14:57 +08:00
{
2014-06-24 06:17:16 +08:00
zend_function * func ;
2004-03-16 18:14:57 +08:00
if ( ! zend_is_executing ( TSRMLS_C ) ) {
if ( space ) {
* space = " " ;
}
return " " ;
}
2014-06-27 03:51:14 +08:00
2014-07-03 02:01:25 +08:00
func = EG ( current_execute_data ) - > func ;
2014-06-24 06:17:16 +08:00
switch ( func - > type ) {
2004-03-16 18:14:57 +08:00
case ZEND_USER_FUNCTION :
case ZEND_INTERNAL_FUNCTION :
{
2014-06-24 06:17:16 +08:00
zend_class_entry * ce = func - > common . scope ;
2004-03-16 18:14:57 +08:00
if ( space ) {
* space = ce ? " :: " : " " ;
}
2014-02-10 14:04:30 +08:00
return ce ? ce - > name - > val : " " ;
2004-03-16 18:14:57 +08:00
}
default :
if ( space ) {
* space = " " ;
}
return " " ;
}
}
2007-11-03 03:40:39 +08:00
/* }}} */
2004-03-16 18:14:57 +08:00
2011-09-13 21:29:35 +08:00
ZEND_API const char * get_active_function_name ( TSRMLS_D ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2014-06-24 06:17:16 +08:00
zend_function * func ;
2002-04-21 04:14:14 +08:00
if ( ! zend_is_executing ( TSRMLS_C ) ) {
return NULL ;
}
2014-07-03 02:01:25 +08:00
func = EG ( current_execute_data ) - > func ;
2014-06-24 06:17:16 +08:00
switch ( func - > type ) {
1999-04-08 02:10:10 +08:00
case ZEND_USER_FUNCTION : {
2014-06-24 06:17:16 +08:00
zend_string * function_name = func - > common . function_name ;
2003-08-07 15:37:19 +08:00
1999-04-08 02:10:10 +08:00
if ( function_name ) {
2014-02-25 18:14:22 +08:00
return function_name - > val ;
1999-04-08 02:10:10 +08:00
} else {
return " main " ;
}
}
break ;
case ZEND_INTERNAL_FUNCTION :
2014-06-24 06:17:16 +08:00
return func - > common . function_name - > val ;
1999-04-08 02:10:10 +08:00
break ;
default :
return NULL ;
}
}
2007-11-03 03:40:39 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2011-09-13 21:29:35 +08:00
ZEND_API const char * zend_get_executed_filename ( TSRMLS_D ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2014-07-03 02:03:21 +08:00
zend_execute_data * ex = EG ( current_execute_data ) ;
while ( ex & & ( ! ex - > func | | ! ZEND_USER_CODE ( ex - > func - > type ) ) ) {
ex = ex - > prev_execute_data ;
}
if ( ex ) {
return ex - > func - > op_array . filename - > val ;
1999-05-26 06:55:13 +08:00
} else {
return " [no active file] " ;
}
1999-04-08 02:10:10 +08:00
}
2007-11-03 03:40:39 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2007-11-03 03:40:39 +08:00
ZEND_API uint zend_get_executed_lineno ( TSRMLS_D ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2014-07-03 02:03:21 +08:00
zend_execute_data * ex = EG ( current_execute_data ) ;
while ( ex & & ( ! ex - > func | | ! ZEND_USER_CODE ( ex - > func - > type ) ) ) {
ex = ex - > prev_execute_data ;
2010-04-02 03:36:56 +08:00
}
2014-07-07 19:50:44 +08:00
if ( ex ) {
2014-07-03 02:03:21 +08:00
if ( EG ( exception ) & & ex - > opline - > opcode = = ZEND_HANDLE_EXCEPTION & &
ex - > opline - > lineno = = 0 & & EG ( opline_before_exception ) ) {
return EG ( opline_before_exception ) - > lineno ;
}
return ex - > opline - > lineno ;
1999-05-26 06:55:13 +08:00
} else {
return 0 ;
}
1999-04-08 02:10:10 +08:00
}
2007-11-03 03:40:39 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2007-11-03 03:40:39 +08:00
ZEND_API zend_bool zend_is_executing ( TSRMLS_D ) /* { { { */
2000-02-04 22:45:58 +08:00
{
2014-07-03 05:02:25 +08:00
return EG ( current_execute_data ) ! = 0 ;
2000-02-04 22:45:58 +08:00
}
2007-11-03 03:40:39 +08:00
/* }}} */
2000-02-04 22:45:58 +08:00
2014-02-10 14:04:30 +08:00
ZEND_API void _zval_ptr_dtor ( zval * zval_ptr ZEND_FILE_LINE_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2013-09-14 20:40:48 +08:00
TSRMLS_FETCH ( ) ;
2014-02-10 14:04:30 +08:00
i_zval_ptr_dtor ( zval_ptr ZEND_FILE_LINE_RELAY_CC TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
}
2007-11-03 03:40:39 +08:00
/* }}} */
2003-08-07 15:37:19 +08:00
2014-02-10 14:04:30 +08:00
ZEND_API void _zval_internal_ptr_dtor ( zval * zval_ptr ZEND_FILE_LINE_DC ) /* { { { */
2003-08-25 01:32:47 +08:00
{
2014-03-05 17:55:56 +08:00
if ( Z_REFCOUNTED_P ( zval_ptr ) ) {
2014-02-17 21:59:18 +08:00
Z_DELREF_P ( zval_ptr ) ;
if ( Z_REFCOUNT_P ( zval_ptr ) = = 0 ) {
_zval_internal_dtor_for_ptr ( zval_ptr ZEND_FILE_LINE_CC ) ;
2014-02-14 21:48:45 +08:00
}
2003-08-25 01:32:47 +08:00
}
}
2007-11-03 03:40:39 +08:00
/* }}} */
2003-08-25 01:32:47 +08:00
2013-12-18 14:25:05 +08:00
ZEND_API int zend_is_true ( zval * op TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2013-12-18 14:25:05 +08:00
return i_zend_is_true ( op TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
}
2007-11-03 03:40:39 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-04-11 16:06:17 +08:00
# define IS_VISITED_CONSTANT 0x80
2007-11-03 03:40:39 +08:00
# define IS_CONSTANT_VISITED(p) (Z_TYPE_P(p) & IS_VISITED_CONSTANT)
2014-04-03 19:26:23 +08:00
# define MARK_CONSTANT_VISITED(p) Z_TYPE_INFO_P(p) |= IS_VISITED_CONSTANT
2007-06-14 00:48:10 +08:00
2014-04-26 04:32:51 +08:00
ZEND_API int zval_update_constant_ex ( zval * p , zend_bool inline_change , zend_class_entry * scope TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2014-05-26 17:25:57 +08:00
zval * const_value ;
2007-06-13 22:50:13 +08:00
char * colon ;
1999-11-22 02:11:10 +08:00
2007-06-14 00:48:10 +08:00
if ( IS_CONSTANT_VISITED ( p ) ) {
zend_error ( E_ERROR , " Cannot declare self-referencing constant '%s' " , Z_STRVAL_P ( p ) ) ;
2014-04-03 19:26:23 +08:00
} else if ( Z_TYPE_P ( p ) = = IS_CONSTANT ) {
2013-11-07 02:21:07 +08:00
int refcount ;
2000-04-27 06:10:06 +08:00
2014-10-09 18:51:05 +08:00
SEPARATE_ZVAL_NOREF ( p ) ;
2013-11-07 02:21:07 +08:00
MARK_CONSTANT_VISITED ( p ) ;
2014-04-03 19:26:23 +08:00
refcount = Z_REFCOUNTED_P ( p ) ? Z_REFCOUNT_P ( p ) : 1 ;
2014-04-25 04:56:15 +08:00
const_value = zend_get_constant_ex ( Z_STR_P ( p ) , scope , Z_CONST_FLAGS_P ( p ) TSRMLS_CC ) ;
if ( ! const_value ) {
2013-11-07 02:21:07 +08:00
char * actual = Z_STRVAL_P ( p ) ;
2008-11-04 23:58:55 +08:00
2013-11-07 02:21:07 +08:00
if ( ( colon = ( char * ) zend_memrchr ( Z_STRVAL_P ( p ) , ' : ' , Z_STRLEN_P ( p ) ) ) ) {
2014-02-14 21:48:45 +08:00
int len ;
2013-11-07 02:21:07 +08:00
zend_error ( E_ERROR , " Undefined class constant '%s' " , Z_STRVAL_P ( p ) ) ;
2014-02-14 21:48:45 +08:00
len = Z_STRLEN_P ( p ) - ( ( colon - Z_STRVAL_P ( p ) ) + 1 ) ;
if ( inline_change ) {
2014-08-26 01:24:55 +08:00
zend_string * tmp = zend_string_init ( colon + 1 , len , 0 ) ;
zend_string_release ( Z_STR_P ( p ) ) ;
2014-02-10 14:04:30 +08:00
Z_STR_P ( p ) = tmp ;
2014-02-14 21:48:45 +08:00
} else {
2014-08-26 01:24:55 +08:00
Z_STR_P ( p ) = zend_string_init ( colon + 1 , len , 0 ) ;
2014-02-14 21:48:45 +08:00
}
2014-04-03 19:26:23 +08:00
Z_TYPE_FLAGS_P ( p ) = IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE ;
2013-11-07 02:21:07 +08:00
} else {
2014-02-14 21:48:45 +08:00
zend_string * save = Z_STR_P ( p ) ;
char * slash ;
2013-11-07 02:21:07 +08:00
int actual_len = Z_STRLEN_P ( p ) ;
2014-04-03 19:26:23 +08:00
if ( ( Z_CONST_FLAGS_P ( p ) & IS_CONSTANT_UNQUALIFIED ) & & ( slash = ( char * ) zend_memrchr ( actual , ' \\ ' , actual_len ) ) ) {
2013-11-07 02:21:07 +08:00
actual = slash + 1 ;
actual_len - = ( actual - Z_STRVAL_P ( p ) ) ;
2008-11-04 23:58:55 +08:00
if ( inline_change ) {
2014-08-26 01:24:55 +08:00
zend_string * s = zend_string_init ( actual , actual_len , 0 ) ;
2014-02-10 14:04:30 +08:00
Z_STR_P ( p ) = s ;
2014-04-03 19:26:23 +08:00
Z_TYPE_FLAGS_P ( p ) = IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE ;
2008-11-04 23:58:55 +08:00
}
2013-11-07 02:21:07 +08:00
}
if ( actual [ 0 ] = = ' \\ ' ) {
if ( inline_change ) {
memmove ( Z_STRVAL_P ( p ) , Z_STRVAL_P ( p ) + 1 , Z_STRLEN_P ( p ) ) ;
- - Z_STRLEN_P ( p ) ;
} else {
+ + actual ;
2008-11-04 23:58:55 +08:00
}
2013-11-07 02:21:07 +08:00
- - actual_len ;
}
2014-04-03 19:26:23 +08:00
if ( ( Z_CONST_FLAGS_P ( p ) & IS_CONSTANT_UNQUALIFIED ) = = 0 ) {
2014-02-14 21:48:45 +08:00
if ( save - > val [ 0 ] = = ' \\ ' ) {
zend_error ( E_ERROR , " Undefined constant '%s' " , save - > val + 1 ) ;
} else {
zend_error ( E_ERROR , " Undefined constant '%s' " , save - > val ) ;
2008-11-04 23:58:55 +08:00
}
2014-02-14 21:48:45 +08:00
if ( inline_change ) {
2014-08-26 01:24:55 +08:00
zend_string_release ( save ) ;
2013-10-31 15:57:12 +08:00
}
2013-11-07 02:21:07 +08:00
save = NULL ;
2008-11-04 23:58:55 +08:00
}
2013-11-07 02:21:07 +08:00
zend_error ( E_NOTICE , " Use of undefined constant %s - assumed '%s' " , actual , actual ) ;
if ( ! inline_change ) {
2014-02-10 14:04:30 +08:00
ZVAL_STRINGL ( p , actual , actual_len ) ;
2014-04-03 19:26:23 +08:00
} else {
2014-09-19 19:41:01 +08:00
Z_TYPE_INFO_P ( p ) = Z_REFCOUNTED_P ( p ) ?
IS_STRING_EX : IS_INTERNED_STRING_EX ;
2014-04-03 19:26:23 +08:00
if ( save & & save - > val ! = actual ) {
2014-08-26 01:24:55 +08:00
zend_string_release ( save ) ;
2014-04-03 19:26:23 +08:00
}
2013-11-07 02:21:07 +08:00
}
}
} else {
2014-02-14 21:48:45 +08:00
if ( inline_change ) {
2014-08-26 01:24:55 +08:00
zend_string_release ( Z_STR_P ( p ) ) ;
2014-02-14 21:48:45 +08:00
}
2014-04-25 04:56:15 +08:00
ZVAL_COPY_VALUE ( p , const_value ) ;
if ( Z_OPT_CONSTANT_P ( p ) ) {
2014-04-26 04:32:51 +08:00
zval_update_constant_ex ( p , 1 , NULL TSRMLS_CC ) ;
2014-04-25 04:56:15 +08:00
}
zval_opt_copy_ctor ( p ) ;
2013-11-07 02:21:07 +08:00
}
2003-06-15 22:46:15 +08:00
2014-03-05 17:55:56 +08:00
if ( Z_REFCOUNTED_P ( p ) ) Z_SET_REFCOUNT_P ( p , refcount ) ;
2013-11-07 02:21:07 +08:00
} else if ( Z_TYPE_P ( p ) = = IS_CONSTANT_AST ) {
2014-05-26 17:25:57 +08:00
zval tmp ;
2014-10-09 18:51:05 +08:00
SEPARATE_ZVAL_NOREF ( p ) ;
2013-11-07 02:21:07 +08:00
2014-04-25 04:56:15 +08:00
zend_ast_evaluate ( & tmp , Z_ASTVAL_P ( p ) , scope TSRMLS_CC ) ;
2013-11-07 02:21:07 +08:00
if ( inline_change ) {
2014-07-27 00:08:31 +08:00
zend_ast_destroy_and_free ( Z_ASTVAL_P ( p ) ) ;
2014-08-28 00:49:56 +08:00
efree_size ( Z_AST_P ( p ) , sizeof ( zend_ast_ref ) ) ;
2001-07-16 19:41:06 +08:00
}
2014-04-25 04:56:15 +08:00
ZVAL_COPY_VALUE ( p , & tmp ) ;
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
}
2007-11-03 03:40:39 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-04-26 04:32:51 +08:00
ZEND_API int zval_update_constant_inline_change ( zval * pp , zend_class_entry * scope TSRMLS_DC ) /* { { { */
2010-05-26 08:00:58 +08:00
{
2014-04-12 01:18:58 +08:00
return zval_update_constant_ex ( pp , 1 , scope TSRMLS_CC ) ;
2010-05-26 08:00:58 +08:00
}
/* }}} */
2014-04-26 04:32:51 +08:00
ZEND_API int zval_update_constant_no_inline_change ( zval * pp , zend_class_entry * scope TSRMLS_DC ) /* { { { */
2010-05-26 08:00:58 +08:00
{
2014-04-12 01:18:58 +08:00
return zval_update_constant_ex ( pp , 0 , scope TSRMLS_CC ) ;
2010-05-26 08:00:58 +08:00
}
/* }}} */
2014-04-26 04:32:51 +08:00
ZEND_API int zval_update_constant ( zval * pp , zend_bool inline_change TSRMLS_DC ) /* { { { */
2006-10-19 00:35:15 +08:00
{
2014-04-12 01:18:58 +08:00
return zval_update_constant_ex ( pp , inline_change , NULL TSRMLS_CC ) ;
2006-10-19 00:35:15 +08:00
}
2007-11-03 03:40:39 +08:00
/* }}} */
1999-08-06 23:24:10 +08:00
2014-08-26 01:28:33 +08:00
int call_user_function ( HashTable * function_table , zval * object , zval * function_name , zval * retval_ptr , uint32_t param_count , zval params [ ] TSRMLS_DC ) /* { { { */
1999-08-06 23:24:10 +08:00
{
2014-05-26 17:16:22 +08:00
return call_user_function_ex ( function_table , object , function_name , retval_ptr , param_count , params , 1 , NULL TSRMLS_CC ) ;
1999-08-06 23:24:10 +08:00
}
2007-11-03 03:40:39 +08:00
/* }}} */
1999-08-06 23:24:10 +08:00
2014-08-26 01:28:33 +08:00
int call_user_function_ex ( HashTable * function_table , zval * object , zval * function_name , zval * retval_ptr , uint32_t param_count , zval params [ ] , int no_separation , zend_array * 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 ;
2014-03-28 06:11:22 +08:00
fci . object = object ? Z_OBJ_P ( object ) : NULL ;
2014-02-10 14:04:30 +08:00
ZVAL_COPY_VALUE ( & fci . function_name , function_name ) ;
fci . retval = retval_ptr ;
2003-08-05 18:24:40 +08:00
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
}
2007-11-03 03:40:39 +08:00
/* }}} */
2003-05-21 00:44:42 +08:00
2007-11-03 03:40:39 +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
{
2014-08-26 01:28:33 +08:00
uint32_t i ;
2002-03-01 22:27:26 +08:00
zend_class_entry * calling_scope = NULL ;
2014-07-03 02:01:25 +08:00
zend_execute_data * call , dummy_execute_data ;
2011-08-07 08:50:46 +08:00
zend_fcall_info_cache fci_cache_local ;
2014-06-24 06:17:16 +08:00
zend_function * func ;
2014-07-03 06:34:43 +08:00
zend_class_entry * orig_scope ;
2014-02-18 05:41:23 +08:00
zval tmp ;
2002-08-23 21:50:42 +08:00
2014-02-18 21:31:27 +08:00
ZVAL_UNDEF ( fci - > retval ) ;
2007-04-27 16:12:24 +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 ;
}
2014-07-03 02:01:25 +08:00
orig_scope = EG ( scope ) ;
2002-08-23 21:50:42 +08:00
/* Initialize execute_data */
2014-07-03 02:01:25 +08:00
if ( ! EG ( current_execute_data ) ) {
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
*/
2014-07-03 02:01:25 +08:00
memset ( & dummy_execute_data , 0 , sizeof ( zend_execute_data ) ) ;
EG ( current_execute_data ) = & dummy_execute_data ;
2014-07-07 19:50:44 +08:00
} else if ( EG ( current_execute_data ) - > func & &
ZEND_USER_CODE ( EG ( current_execute_data ) - > func - > common . type ) & &
2014-07-03 02:01:25 +08:00
EG ( current_execute_data ) - > opline - > opcode ! = ZEND_DO_FCALL ) {
/* Insert fake frame in case of include or magic calls */
dummy_execute_data = * EG ( current_execute_data ) ;
dummy_execute_data . prev_execute_data = EG ( current_execute_data ) ;
dummy_execute_data . call = NULL ;
dummy_execute_data . opline = NULL ;
dummy_execute_data . func = NULL ;
EG ( current_execute_data ) = & dummy_execute_data ;
2004-02-05 07:48:39 +08:00
}
2000-01-16 06:52:24 +08:00
2003-08-05 18:24:40 +08:00
if ( ! fci_cache | | ! fci_cache - > initialized ) {
2014-02-25 20:03:34 +08:00
zend_string * callable_name ;
2008-07-26 21:14:04 +08:00
char * error = NULL ;
2000-06-03 11:28:08 +08:00
2008-07-26 21:14:04 +08:00
if ( ! fci_cache ) {
fci_cache = & fci_cache_local ;
2003-07-02 22:44:41 +08:00
}
2014-03-28 06:11:22 +08:00
if ( ! zend_is_callable_ex ( & fci - > function_name , fci - > object , IS_CALLABLE_CHECK_SILENT , & callable_name , fci_cache , & error TSRMLS_CC ) ) {
2008-07-26 21:14:04 +08:00
if ( error ) {
2014-02-25 20:03:34 +08:00
zend_error ( E_WARNING , " Invalid callback %s, %s " , callable_name - > val , error ) ;
2008-07-26 21:14:04 +08:00
efree ( error ) ;
2008-07-14 17:49:03 +08:00
}
2008-07-27 03:14:38 +08:00
if ( callable_name ) {
2014-08-26 01:24:55 +08:00
zend_string_release ( callable_name ) ;
2008-07-27 03:14:38 +08:00
}
2014-07-03 02:01:25 +08:00
if ( EG ( current_execute_data ) = = & dummy_execute_data ) {
EG ( current_execute_data ) = dummy_execute_data . prev_execute_data ;
}
1999-04-08 02:10:10 +08:00
return FAILURE ;
2008-07-26 21:14:04 +08:00
} else if ( error ) {
/* Capitalize the first latter of the error message */
if ( error [ 0 ] > = ' a ' & & error [ 0 ] < = ' z ' ) {
error [ 0 ] + = ( ' A ' - ' a ' ) ;
2003-07-03 17:18:41 +08:00
}
2008-07-26 21:14:04 +08:00
zend_error ( E_STRICT , " %s " , error ) ;
efree ( error ) ;
2003-05-21 00:44:42 +08:00
}
2014-08-26 01:24:55 +08:00
zend_string_release ( callable_name ) ;
2008-07-26 21:14:04 +08:00
}
2008-07-14 17:49:03 +08:00
2014-06-24 06:17:16 +08:00
func = fci_cache - > function_handler ;
2014-10-07 21:12:12 +08:00
call = zend_vm_stack_push_call_frame ( VM_FRAME_TOP_FUNCTION ,
func , fci - > param_count , fci_cache - > called_scope , fci_cache - > object , NULL TSRMLS_CC ) ;
2008-07-26 21:14:04 +08:00
calling_scope = fci_cache - > calling_scope ;
2014-04-24 19:53:20 +08:00
fci - > object = fci_cache - > object ;
2014-03-28 06:11:22 +08:00
if ( fci - > object & &
2014-02-12 22:08:11 +08:00
( ! EG ( objects_store ) . object_buckets | |
2014-04-09 05:50:15 +08:00
! IS_OBJ_VALID ( EG ( objects_store ) . object_buckets [ fci - > object - > handle ] ) ) ) {
2014-07-03 02:01:25 +08:00
if ( EG ( current_execute_data ) = = & dummy_execute_data ) {
EG ( current_execute_data ) = dummy_execute_data . prev_execute_data ;
}
2014-02-12 22:08:11 +08:00
return FAILURE ;
}
2006-05-10 07:53:23 +08:00
2014-06-24 06:17:16 +08:00
if ( func - > common . fn_flags & ( ZEND_ACC_ABSTRACT | ZEND_ACC_DEPRECATED ) ) {
if ( func - > common . fn_flags & ZEND_ACC_ABSTRACT ) {
zend_error_noreturn ( E_ERROR , " Cannot call abstract method %s::%s() " , func - > common . scope - > name - > val , func - > common . function_name - > val ) ;
2006-02-26 02:25:45 +08:00
}
2014-06-24 06:17:16 +08:00
if ( func - > common . fn_flags & ZEND_ACC_DEPRECATED ) {
2008-03-10 04:52:29 +08:00
zend_error ( E_DEPRECATED , " Function %s%s%s() is deprecated " ,
2014-06-24 06:17:16 +08:00
func - > common . scope ? func - > common . scope - > name - > val : " " ,
func - > common . scope ? " :: " : " " ,
func - > common . function_name - > val ) ;
2006-02-26 02:25:45 +08:00
}
}
2003-08-07 15:37:19 +08:00
2003-08-05 18:24:40 +08:00
for ( i = 0 ; i < fci - > param_count ; i + + ) {
2014-02-18 05:41:23 +08:00
zval * param ;
1999-04-08 02:10:10 +08:00
2014-06-24 06:17:16 +08:00
if ( ARG_SHOULD_BE_SENT_BY_REF ( func , i + 1 ) ) {
2014-05-06 08:35:29 +08:00
// TODO: Scalar values don't have reference counters anymore.
// They are assumed to be 1, and they may be easily passed by
// reference now. However, previously scalars with refcount==1
// might be passed and with refcount>1 might not. We can support
// only single behavior ???
#if 0
if ( Z_REFCOUNTED ( fci - > params [ i ] ) & &
// This solution breaks the following test (omit warning message) ???
// Zend/tests/bug61273.phpt
// ext/reflection/tests/bug42976.phpt
// ext/standard/tests/general_functions/call_user_func_array_variation_001.phpt
# else
2014-03-05 20:17:00 +08:00
if ( ! Z_REFCOUNTED ( fci - > params [ i ] ) | |
2014-05-06 08:35:29 +08:00
// This solution breaks the following test (emit warning message) ???
// ext/pdo_sqlite/tests/pdo_005.phpt
# endif
2014-03-05 20:17:00 +08:00
( ! Z_ISREF ( fci - > params [ i ] ) & & Z_REFCOUNT ( fci - > params [ i ] ) > 1 ) ) {
if ( fci - > no_separation & &
2014-06-24 06:17:16 +08:00
! ARG_MAY_BE_SENT_BY_REF ( func , i + 1 ) ) {
2014-06-27 03:51:14 +08:00
if ( i ) {
2014-03-05 20:17:00 +08:00
/* hack to clean up the stack */
2014-07-03 02:01:25 +08:00
call - > num_args = i ;
zend_vm_stack_free_args ( call TSRMLS_CC ) ;
2005-05-19 02:02:50 +08:00
}
2014-07-03 02:01:25 +08:00
zend_vm_stack_free_call_frame ( call TSRMLS_CC ) ;
2006-12-21 19:08:00 +08:00
2014-03-05 20:17:00 +08:00
zend_error ( E_WARNING , " Parameter %d to %s%s%s() expected to be a reference, value given " ,
i + 1 ,
2014-06-24 06:17:16 +08:00
func - > common . scope ? func - > common . scope - > name - > val : " " ,
func - > common . scope ? " :: " : " " ,
func - > common . function_name - > val ) ;
2014-07-03 02:01:25 +08:00
if ( EG ( current_execute_data ) = = & dummy_execute_data ) {
EG ( current_execute_data ) = dummy_execute_data . prev_execute_data ;
}
2014-03-05 20:17:00 +08:00
return FAILURE ;
1999-08-06 23:24:10 +08:00
}
2014-03-05 20:17:00 +08:00
2014-03-12 02:33:28 +08:00
if ( Z_REFCOUNTED ( fci - > params [ i ] ) ) {
Z_DELREF ( fci - > params [ i ] ) ;
}
ZVAL_DUP ( & tmp , & fci - > params [ i ] ) ;
ZVAL_NEW_REF ( & fci - > params [ i ] , & tmp ) ;
Z_ADDREF ( fci - > params [ i ] ) ;
2014-03-05 20:17:00 +08:00
} else if ( ! Z_ISREF ( fci - > params [ i ] ) ) {
ZVAL_NEW_REF ( & fci - > params [ i ] , & fci - > params [ i ] ) ;
2014-03-20 21:03:32 +08:00
Z_ADDREF ( fci - > params [ i ] ) ;
2014-03-05 20:17:00 +08:00
} else if ( Z_REFCOUNTED ( fci - > params [ i ] ) ) {
2014-02-21 22:39:27 +08:00
Z_ADDREF ( fci - > params [ i ] ) ;
1999-08-06 23:24:10 +08:00
}
2014-07-03 02:01:25 +08:00
param = ZEND_CALL_ARG ( call , i + 1 ) ;
2014-06-27 03:51:14 +08:00
ZVAL_COPY_VALUE ( param , & fci - > params [ i ] ) ;
2014-02-10 14:04:30 +08:00
} else if ( Z_ISREF ( fci - > params [ i ] ) & &
2010-10-01 19:53:04 +08:00
/* don't separate references for __call */
2014-06-24 06:17:16 +08:00
( func - > common . fn_flags & ZEND_ACC_CALL_VIA_HANDLER ) = = 0 ) {
2014-07-03 02:01:25 +08:00
param = ZEND_CALL_ARG ( call , i + 1 ) ;
2014-03-06 05:04:28 +08:00
ZVAL_DUP ( param , Z_REFVAL ( fci - > params [ i ] ) ) ;
2014-02-18 21:31:27 +08:00
} else {
2014-07-03 02:01:25 +08:00
param = ZEND_CALL_ARG ( call , i + 1 ) ;
2014-02-18 21:31:27 +08:00
ZVAL_COPY ( param , & fci - > params [ i ] ) ;
1999-08-06 23:24:10 +08:00
}
1999-04-08 02:10:10 +08:00
}
2014-07-03 02:01:25 +08:00
call - > num_args = fci - > param_count ;
1999-04-08 02:10:10 +08:00
2002-03-01 22:27:26 +08:00
EG ( scope ) = calling_scope ;
2014-10-06 05:11:17 +08:00
if ( func - > common . fn_flags & ZEND_ACC_STATIC ) {
fci - > object = NULL ;
}
if ( ! fci - > object ) {
2014-10-03 23:32:46 +08:00
Z_OBJ ( call - > This ) = NULL ;
Z_TYPE_INFO ( call - > This ) = IS_UNDEF ;
2002-01-15 00:55:23 +08:00
} else {
2014-10-03 23:32:46 +08:00
ZVAL_OBJ ( & call - > This , fci - > object ) ;
GC_REFCOUNT ( fci - > object ) + + ;
2002-01-05 23:18:30 +08:00
}
2014-06-24 06:17:16 +08:00
if ( func - > type = = ZEND_USER_FUNCTION ) {
EG ( scope ) = func - > common . scope ;
2014-07-04 22:03:45 +08:00
call - > symbol_table = fci - > symbol_table ;
2014-07-03 02:03:21 +08:00
if ( EXPECTED ( ( func - > op_array . fn_flags & ZEND_ACC_GENERATOR ) = = 0 ) ) {
2014-10-07 21:12:12 +08:00
zend_init_execute_data ( call , & func - > op_array , fci - > retval TSRMLS_CC ) ;
2014-07-07 19:50:44 +08:00
zend_execute_ex ( call TSRMLS_CC ) ;
2014-05-24 21:37:15 +08:00
} else {
2014-07-07 19:50:44 +08:00
zend_generator_create_zval ( call , & func - > op_array , fci - > retval TSRMLS_CC ) ;
2012-07-20 06:49:50 +08:00
}
2014-06-24 06:17:16 +08:00
} else if ( func - > type = = ZEND_INTERNAL_FUNCTION ) {
int call_via_handler = ( func - > common . fn_flags & ZEND_ACC_CALL_VIA_HANDLER ) ! = 0 ;
2014-03-06 17:32:43 +08:00
ZVAL_NULL ( fci - > retval ) ;
2014-06-24 06:17:16 +08:00
if ( func - > common . scope ) {
EG ( scope ) = func - > common . scope ;
2003-09-12 01:04:26 +08:00
}
2014-07-03 02:01:25 +08:00
call - > prev_execute_data = EG ( current_execute_data ) ;
2014-07-31 14:51:49 +08:00
call - > return_value = NULL ; /* this is not a constructor call */
2014-07-03 02:01:25 +08:00
EG ( current_execute_data ) = call ;
2013-08-27 01:06:36 +08:00
if ( EXPECTED ( zend_execute_internal = = NULL ) ) {
2012-07-23 05:25:00 +08:00
/* saves one function call if zend_execute_internal is not used */
2014-10-03 23:32:46 +08:00
func - > internal_function . handler ( call , fci - > retval TSRMLS_CC ) ;
2012-07-23 05:25:00 +08:00
} else {
2014-07-07 19:50:44 +08:00
zend_execute_internal ( call , fci - > retval TSRMLS_CC ) ;
2012-07-23 05:25:00 +08:00
}
2014-07-03 02:01:25 +08:00
EG ( current_execute_data ) = call - > prev_execute_data ;
zend_vm_stack_free_args ( call TSRMLS_CC ) ;
zend_vm_stack_free_call_frame ( call TSRMLS_CC ) ;
2014-06-27 03:51:14 +08:00
2007-11-03 03:40:39 +08:00
/* We shouldn't fix bad extensions here,
because it can break proper ones ( Bug # 34045 )
if ( ! EX ( function_state ) . function - > common . return_reference )
{
2014-05-24 21:45:07 +08:00
INIT_PZVAL ( f - > retval ) ;
2007-11-03 03:40:39 +08:00
} */
2014-05-24 21:37:15 +08:00
if ( EG ( exception ) ) {
2014-02-10 14:04:30 +08:00
zval_ptr_dtor ( fci - > retval ) ;
ZVAL_UNDEF ( fci - > retval ) ;
2008-01-15 02:13:12 +08:00
}
2008-07-26 21:14:04 +08:00
if ( call_via_handler ) {
/* We must re-initialize function again */
fci_cache - > initialized = 0 ;
}
2008-07-27 01:01:40 +08:00
} else { /* ZEND_OVERLOADED_FUNCTION */
2014-04-16 01:56:30 +08:00
ZVAL_NULL ( fci - > retval ) ;
2008-07-27 01:01:40 +08:00
2008-08-08 21:21:52 +08:00
/* Not sure what should be done here if it's a static method */
2014-03-28 06:11:22 +08:00
if ( fci - > object ) {
2014-07-03 02:01:25 +08:00
call - > prev_execute_data = EG ( current_execute_data ) ;
EG ( current_execute_data ) = call ;
2014-10-03 23:32:46 +08:00
fci - > object - > handlers - > call_method ( func - > common . function_name , fci - > object , call , fci - > retval TSRMLS_CC ) ;
2014-07-03 02:01:25 +08:00
EG ( current_execute_data ) = call - > prev_execute_data ;
2008-07-27 01:01:40 +08:00
} else {
zend_error_noreturn ( E_ERROR , " Cannot call overloaded function for non-object " ) ;
}
2014-07-03 02:01:25 +08:00
zend_vm_stack_free_args ( call TSRMLS_CC ) ;
zend_vm_stack_free_call_frame ( call TSRMLS_CC ) ;
2014-06-24 06:17:16 +08:00
if ( func - > type = = ZEND_OVERLOADED_FUNCTION_TEMPORARY ) {
2014-08-26 01:24:55 +08:00
zend_string_release ( func - > common . function_name ) ;
2008-07-27 01:01:40 +08:00
}
2014-06-24 06:17:16 +08:00
efree ( func ) ;
2008-07-27 01:01:40 +08:00
2014-05-24 21:37:15 +08:00
if ( EG ( exception ) ) {
2014-02-10 14:04:30 +08:00
zval_ptr_dtor ( fci - > retval ) ;
ZVAL_UNDEF ( fci - > retval ) ;
2008-07-27 01:01:40 +08:00
}
1999-04-08 02:10:10 +08:00
}
2014-10-06 05:11:17 +08:00
if ( fci - > object ) {
2014-10-03 23:32:46 +08:00
OBJ_RELEASE ( fci - > object ) ;
2014-03-28 06:11:22 +08:00
}
2014-04-24 19:53:20 +08:00
2014-07-03 02:01:25 +08:00
EG ( scope ) = orig_scope ;
if ( EG ( current_execute_data ) = = & dummy_execute_data ) {
EG ( current_execute_data ) = dummy_execute_data . 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
}
2007-11-03 03:40:39 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-04-17 19:40:45 +08:00
ZEND_API zend_class_entry * zend_lookup_class_ex ( zend_string * name , const zval * key , int use_autoload TSRMLS_DC ) /* { { { */
2002-06-17 02:25:05 +08:00
{
2014-02-10 14:04:30 +08:00
zend_class_entry * ce = NULL ;
zval args [ 1 ] ;
zval local_retval ;
int retval ;
zend_string * lc_name ;
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
2010-04-20 18:57:45 +08:00
if ( key ) {
2014-04-17 19:40:45 +08:00
lc_name = Z_STR_P ( key ) ;
2010-04-20 18:57:45 +08:00
} else {
2014-02-10 14:04:30 +08:00
if ( name = = NULL | | ! name - > len ) {
return NULL ;
2010-04-20 18:57:45 +08:00
}
2007-11-03 03:40:39 +08:00
2014-02-10 14:04:30 +08:00
if ( name - > val [ 0 ] = = ' \\ ' ) {
2014-08-26 01:24:55 +08:00
lc_name = zend_string_alloc ( name - > len - 1 , 0 ) ;
2014-02-10 14:04:30 +08:00
zend_str_tolower_copy ( lc_name - > val , name - > val + 1 , name - > len - 1 ) ;
} else {
2014-08-26 01:24:55 +08:00
lc_name = zend_string_alloc ( name - > len , 0 ) ;
2014-02-10 14:04:30 +08:00
zend_str_tolower_copy ( lc_name - > val , name - > val , name - > len ) ;
2010-04-20 18:57:45 +08:00
}
}
2009-04-08 21:17:58 +08:00
2014-02-10 14:04:30 +08:00
ce = zend_hash_find_ptr ( EG ( class_table ) , lc_name ) ;
if ( ce ) {
2010-04-20 18:57:45 +08:00
if ( ! key ) {
2014-08-26 01:24:55 +08:00
zend_string_free ( lc_name ) ;
2010-04-20 18:57:45 +08:00
}
2014-02-10 14:04:30 +08:00
return ce ;
2002-06-26 23:13:14 +08:00
}
2004-03-28 17:37:30 +08:00
/* The compiler is not-reentrant. Make sure we __autoload() only during run-time
2013-07-24 07:55:43 +08:00
* ( doesn ' t impact functionality of __autoload ( )
2004-03-28 17:37:30 +08:00
*/
2005-09-09 14:48:49 +08:00
if ( ! use_autoload | | zend_is_compiling ( TSRMLS_C ) ) {
2010-04-20 18:57:45 +08:00
if ( ! key ) {
2014-08-26 01:24:55 +08:00
zend_string_free ( lc_name ) ;
2010-04-20 18:57:45 +08:00
}
2014-02-10 14:04:30 +08:00
return NULL ;
2004-03-28 17:37:30 +08:00
}
2014-04-22 05:41:40 +08:00
if ( ! EG ( autoload_func ) ) {
zend_function * func = zend_hash_str_find_ptr ( EG ( function_table ) , ZEND_AUTOLOAD_FUNC_NAME , sizeof ( ZEND_AUTOLOAD_FUNC_NAME ) - 1 ) ;
if ( func ) {
EG ( autoload_func ) = func ;
} else {
if ( ! key ) {
2014-08-26 01:24:55 +08:00
zend_string_free ( lc_name ) ;
2014-04-22 05:41:40 +08:00
}
return NULL ;
}
}
2013-11-29 16:53:02 +08:00
/* Verify class name before passing it to __autoload() */
2014-02-10 14:04:30 +08:00
if ( strspn ( name - > val , " 0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ \177 \200 \201 \202 \203 \204 \205 \206 \207 \210 \211 \212 \213 \214 \215 \216 \217 \220 \221 \222 \223 \224 \225 \226 \227 \230 \231 \232 \233 \234 \235 \236 \237 \240 \241 \242 \243 \244 \245 \246 \247 \250 \251 \252 \253 \254 \255 \256 \257 \260 \261 \262 \263 \264 \265 \266 \267 \270 \271 \272 \273 \274 \275 \276 \277 \300 \301 \302 \303 \304 \305 \306 \307 \310 \311 \312 \313 \314 \315 \316 \317 \320 \321 \322 \323 \324 \325 \326 \327 \330 \331 \332 \333 \334 \335 \336 \337 \340 \341 \342 \343 \344 \345 \346 \347 \350 \351 \352 \353 \354 \355 \356 \357 \360 \361 \362 \363 \364 \365 \366 \367 \370 \371 \372 \373 \374 \375 \376 \377 \\ " ) ! = name - > len ) {
2013-11-29 16:53:02 +08:00
if ( ! key ) {
2014-08-26 01:24:55 +08:00
zend_string_free ( lc_name ) ;
2013-11-29 16:53:02 +08:00
}
2014-02-10 14:04:30 +08:00
return NULL ;
2013-11-29 16:53:02 +08:00
}
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 ) ) ;
2014-04-21 22:25:34 +08:00
zend_hash_init ( EG ( in_autoload ) , 8 , NULL , NULL , 0 ) ;
2004-03-24 22:30:59 +08:00
}
2007-11-03 03:40:39 +08:00
2014-02-10 14:04:30 +08:00
if ( zend_hash_add_empty_element ( EG ( in_autoload ) , lc_name ) = = NULL ) {
2010-04-20 18:57:45 +08:00
if ( ! key ) {
2014-08-26 01:24:55 +08:00
zend_string_free ( lc_name ) ;
2010-04-20 18:57:45 +08:00
}
2014-02-10 14:04:30 +08:00
return NULL ;
2003-12-23 18:45:10 +08:00
}
2014-02-10 14:04:30 +08:00
ZVAL_UNDEF ( & local_retval ) ;
2002-06-17 02:25:05 +08:00
2014-02-10 14:04:30 +08:00
if ( name - > val [ 0 ] = = ' \\ ' ) {
ZVAL_STRINGL ( & args [ 0 ] , name - > val + 1 , name - > len - 1 ) ;
2010-03-03 08:15:34 +08:00
} else {
2014-09-19 21:32:50 +08:00
ZVAL_STR_COPY ( & args [ 0 ] , name ) ;
2010-03-03 08:15:34 +08:00
}
2007-11-03 03:40:39 +08:00
2004-08-24 04:57:40 +08:00
fcall_info . size = sizeof ( fcall_info ) ;
fcall_info . function_table = EG ( function_table ) ;
2014-09-19 21:32:50 +08:00
ZVAL_STR_COPY ( & fcall_info . function_name , EG ( autoload_func ) - > common . function_name ) ;
2004-08-24 04:57:40 +08:00
fcall_info . symbol_table = NULL ;
2014-02-10 14:04:30 +08:00
fcall_info . retval = & local_retval ;
2004-08-24 04:57:40 +08:00
fcall_info . param_count = 1 ;
fcall_info . params = args ;
2014-03-28 06:11:22 +08:00
fcall_info . object = NULL ;
2004-08-24 04:57:40 +08:00
fcall_info . no_separation = 1 ;
2014-04-22 05:41:40 +08:00
fcall_cache . initialized = 1 ;
2004-08-24 04:57:40 +08:00
fcall_cache . function_handler = EG ( autoload_func ) ;
fcall_cache . calling_scope = NULL ;
2008-07-25 16:23:07 +08:00
fcall_cache . called_scope = NULL ;
2014-03-28 06:11:22 +08:00
fcall_cache . object = NULL ;
2002-06-26 23:13:14 +08:00
2008-08-14 18:24:52 +08:00
zend_exception_save ( TSRMLS_C ) ;
2004-08-24 04:57:40 +08:00
retval = zend_call_function ( & fcall_info , & fcall_cache TSRMLS_CC ) ;
2008-09-15 18:19:53 +08:00
zend_exception_restore ( TSRMLS_C ) ;
2014-02-10 14:04:30 +08:00
zval_ptr_dtor ( & args [ 0 ] ) ;
2014-02-19 05:12:05 +08:00
zval_dtor ( & fcall_info . function_name ) ;
2005-05-26 22:28:24 +08:00
2014-02-10 14:04:30 +08:00
zend_hash_del ( EG ( in_autoload ) , lc_name ) ;
2003-12-23 18:45:10 +08:00
2014-02-10 14:04:30 +08:00
zval_ptr_dtor ( & local_retval ) ;
2002-06-26 23:13:14 +08:00
2010-04-20 18:57:45 +08:00
if ( retval = = SUCCESS ) {
2014-02-10 14:04:30 +08:00
ce = zend_hash_find_ptr ( EG ( class_table ) , lc_name ) ;
2010-04-20 18:57:45 +08:00
}
if ( ! key ) {
2014-08-26 01:24:55 +08:00
zend_string_free ( lc_name ) ;
2002-08-14 00:46:40 +08:00
}
2014-02-10 14:04:30 +08:00
return ce ;
2002-06-26 23:13:14 +08:00
}
2007-11-03 03:40:39 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-02-10 14:04:30 +08:00
ZEND_API zend_class_entry * zend_lookup_class ( zend_string * name TSRMLS_DC ) /* { { { */
2005-09-09 14:48:49 +08:00
{
2014-02-10 14:04:30 +08:00
return zend_lookup_class_ex ( name , NULL , 1 TSRMLS_CC ) ;
2005-09-09 14:48:49 +08:00
}
2007-11-03 03:40:39 +08:00
/* }}} */
2005-09-09 14:48:49 +08:00
2009-06-06 02:50:32 +08:00
ZEND_API int zend_eval_stringl ( char * str , int str_len , zval * retval_ptr , char * string_name TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
zval pv ;
zend_op_array * new_op_array ;
2014-08-26 01:28:33 +08:00
uint32_t original_compiler_options ;
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 ) {
2014-08-26 01:24:55 +08:00
ZVAL_NEW_STR ( & pv , zend_string_alloc ( str_len + sizeof ( " return ; " ) - 1 , 1 ) ) ;
2007-11-03 03:40:39 +08:00
memcpy ( Z_STRVAL ( pv ) , " return " , sizeof ( " return " ) - 1 ) ;
2009-06-06 02:50:32 +08:00
memcpy ( Z_STRVAL ( pv ) + sizeof ( " return " ) - 1 , str , str_len ) ;
2007-11-03 03:40:39 +08:00
Z_STRVAL ( pv ) [ Z_STRLEN ( pv ) - 1 ] = ' ; ' ;
2006-12-28 08:17:48 +08:00
Z_STRVAL ( pv ) [ Z_STRLEN ( pv ) ] = ' \0 ' ;
1999-04-08 02:10:10 +08:00
} else {
2014-02-10 14:04:30 +08:00
ZVAL_STRINGL ( & pv , str , str_len ) ;
1999-04-08 02:10:10 +08:00
}
/*printf("Evaluating '%s'\n", pv.value.str.val);*/
2008-03-18 16:36:30 +08:00
original_compiler_options = CG ( compiler_options ) ;
CG ( compiler_options ) = ZEND_COMPILE_DEFAULT_FOR_EVAL ;
2006-06-13 20:57:48 +08:00
new_op_array = zend_compile_string ( & pv , string_name TSRMLS_CC ) ;
2008-03-18 16:36:30 +08:00
CG ( compiler_options ) = original_compiler_options ;
1999-04-08 02:10:10 +08:00
if ( new_op_array ) {
2014-02-12 18:29:51 +08:00
zval local_retval ;
2003-08-07 15:37:19 +08:00
2014-07-04 22:03:45 +08:00
EG ( no_extensions ) = 1 ;
1999-12-20 02:54:40 +08:00
2011-11-13 01:05:08 +08:00
zend_try {
2014-02-12 18:29:51 +08:00
ZVAL_UNDEF ( & local_retval ) ;
zend_execute ( new_op_array , & local_retval TSRMLS_CC ) ;
2012-01-29 23:25:40 +08:00
} zend_catch {
2012-02-08 11:03:05 +08:00
destroy_op_array ( new_op_array TSRMLS_CC ) ;
2014-08-28 00:49:56 +08:00
efree_size ( new_op_array , sizeof ( zend_op_array ) ) ;
2012-02-08 11:03:05 +08:00
zend_bailout ( ) ;
2011-11-13 01:05:08 +08:00
} zend_end_try ( ) ;
1999-12-20 02:54:40 +08:00
2014-02-12 18:29:51 +08:00
if ( Z_TYPE ( local_retval ) ! = IS_UNDEF ) {
if ( retval_ptr ) {
2014-04-15 19:40:40 +08:00
ZVAL_COPY_VALUE ( retval_ptr , & local_retval ) ;
2014-02-12 18:29:51 +08:00
} else {
zval_ptr_dtor ( & local_retval ) ;
}
} else {
if ( retval_ptr ) {
ZVAL_NULL ( retval_ptr ) ;
}
}
1999-12-20 02:54:40 +08:00
1999-04-08 02:10:10 +08:00
EG ( no_extensions ) = 0 ;
2003-03-26 15:44:11 +08:00
destroy_op_array ( new_op_array TSRMLS_CC ) ;
2014-08-28 00:49:56 +08:00
efree_size ( new_op_array , sizeof ( zend_op_array ) ) ;
2012-02-08 11:03:05 +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
}
2014-02-24 20:35:55 +08:00
zval_dtor ( & pv ) ;
2000-05-07 02:49:46 +08:00
return retval ;
1999-04-08 02:10:10 +08:00
}
2007-11-03 03:40:39 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-06-06 02:50:32 +08:00
ZEND_API int zend_eval_string ( char * str , zval * retval_ptr , char * string_name TSRMLS_DC ) /* { { { */
{
return zend_eval_stringl ( str , strlen ( str ) , retval_ptr , string_name TSRMLS_CC ) ;
}
/* }}} */
ZEND_API int zend_eval_stringl_ex ( char * str , int str_len , zval * retval_ptr , char * string_name , int handle_exceptions TSRMLS_DC ) /* { { { */
2003-08-24 21:10:03 +08:00
{
int result ;
2009-06-06 02:50:32 +08:00
result = zend_eval_stringl ( str , str_len , retval_ptr , string_name TSRMLS_CC ) ;
2003-08-24 21:10:03 +08:00
if ( handle_exceptions & & EG ( exception ) ) {
2009-01-02 21:14:49 +08:00
zend_exception_error ( EG ( exception ) , E_ERROR TSRMLS_CC ) ;
2003-08-24 21:10:03 +08:00
result = FAILURE ;
}
return result ;
}
2007-11-03 03:40:39 +08:00
/* }}} */
2003-08-24 21:10:03 +08:00
2009-06-06 02:50:32 +08:00
ZEND_API int zend_eval_string_ex ( char * str , zval * retval_ptr , char * string_name , int handle_exceptions TSRMLS_DC ) /* { { { */
{
return zend_eval_stringl_ex ( str , strlen ( str ) , retval_ptr , string_name , handle_exceptions TSRMLS_CC ) ;
}
/* }}} */
2007-11-03 03:40:39 +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 ) {
2011-09-08 17:17:21 +08:00
# ifdef ZEND_SIGNALS
2012-07-23 05:25:00 +08:00
/*
2011-09-08 02:48:17 +08:00
We got here because we got a timeout signal , so we are in a signal handler
at this point . However , we want to be able to timeout any user - supplied
shutdown functions , so pretend we are not in a signal handler while we are
2012-07-23 05:25:00 +08:00
calling these
2011-09-08 02:48:17 +08:00
*/
SIGG ( running ) = 0 ;
2011-09-08 17:17:21 +08:00
# endif
2002-09-19 23:58:01 +08:00
zend_on_timeout ( EG ( timeout_seconds ) TSRMLS_CC ) ;
}
2003-01-23 13:15:42 +08:00
2014-08-26 05:05:05 +08:00
zend_error ( E_ERROR , " Maximum execution time of %pd second%s exceeded " , EG ( timeout_seconds ) , EG ( timeout_seconds ) = = 1 ? " " : " s " ) ;
2000-06-16 09:54:56 +08:00
}
2007-11-03 03:40:39 +08:00
/* }}} */
2000-06-16 09:54:56 +08:00
2000-06-16 10:49:21 +08:00
# ifdef ZEND_WIN32
2007-11-03 03:40:39 +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 */
2007-11-03 03:40:39 +08:00
if ( lParam = = 0 ) {
2000-06-26 23:17:36 +08:00
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
}
2007-11-03 03:40:39 +08:00
/* }}} */
2000-06-16 09:54:56 +08:00
2007-11-03 03:40:39 +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
}
2007-11-03 03:40:39 +08:00
/* }}} */
2000-06-16 09:54:56 +08:00
2007-11-03 03:40:39 +08:00
void zend_init_timeout_thread ( void ) /* { { { */
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
}
2007-11-03 03:40:39 +08:00
/* }}} */
2000-06-16 09:54:56 +08:00
2007-11-03 03:40:39 +08:00
void zend_shutdown_timeout_thread ( void ) /* { { { */
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
}
2007-11-03 03:40:39 +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
2014-08-26 01:24:55 +08:00
void zend_set_timeout ( zend_long seconds , int reset_signals ) /* { { { */
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
EG ( timeout_seconds ) = seconds ;
2008-03-19 23:22:17 +08:00
2000-06-16 09:54:56 +08:00
# ifdef ZEND_WIN32
2008-03-19 23:30:49 +08:00
if ( ! seconds ) {
return ;
}
2007-11-03 03:40:39 +08:00
if ( timeout_thread_initialized = = 0 & & InterlockedIncrement ( & timeout_thread_initialized ) = = 1 ) {
2000-06-16 22:27:28 +08:00
/* 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 ( ) ;
}
2008-03-19 23:30:49 +08:00
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 */
2011-06-03 05:16:50 +08:00
int signo ;
2000-06-16 09:54:56 +08:00
2008-03-19 23:22:17 +08:00
if ( seconds ) {
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__
2008-03-19 23:22:17 +08:00
setitimer ( ITIMER_REAL , & t_r , NULL ) ;
}
2011-06-03 05:16:50 +08:00
signo = SIGALRM ;
2005-07-12 14:52:59 +08:00
# else
2008-03-19 23:22:17 +08:00
setitimer ( ITIMER_PROF , & t_r , NULL ) ;
}
2011-06-03 05:16:50 +08:00
signo = SIGPROF ;
2005-07-12 14:52:59 +08:00
# endif
2011-06-03 05:16:50 +08:00
if ( reset_signals ) {
# ifdef ZEND_SIGNALS
zend_signal ( signo , zend_timeout TSRMLS_CC ) ;
# else
sigset_t sigset ;
signal ( signo , zend_timeout ) ;
sigemptyset ( & sigset ) ;
sigaddset ( & sigset , signo ) ;
2008-03-19 05:42:50 +08:00
sigprocmask ( SIG_UNBLOCK , & sigset , NULL ) ;
2011-06-03 05:16:50 +08:00
# endif
2008-03-19 05:42:50 +08:00
}
2000-06-16 10:49:21 +08:00
}
2011-06-03 05:16:50 +08:00
# endif /* HAVE_SETITIMER */
2000-06-16 09:54:56 +08:00
# endif
}
2007-11-03 03:40:39 +08:00
/* }}} */
2000-06-16 09:54:56 +08:00
2007-11-03 03:40:39 +08:00
void zend_unset_timeout ( TSRMLS_D ) /* { { { */
2000-06-16 09:54:56 +08:00
{
# ifdef ZEND_WIN32
2006-11-10 19:49:35 +08:00
if ( timeout_thread_initialized ) {
PostThreadMessage ( timeout_thread_id , WM_UNREGISTER_ZEND_TIMEOUT , ( WPARAM ) GetCurrentThreadId ( ) , ( LPARAM ) 0 ) ;
}
2000-06-16 09:54:56 +08:00
# else
# ifdef HAVE_SETITIMER
2009-11-05 17:33:19 +08:00
if ( EG ( timeout_seconds ) ) {
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
}
2007-11-03 03:40:39 +08:00
/* }}} */
2003-02-01 09:49:15 +08:00
2014-02-10 14:04:30 +08:00
zend_class_entry * zend_fetch_class ( zend_string * class_name , int fetch_type TSRMLS_DC ) /* { { { */
2003-08-03 16:21:08 +08:00
{
2014-02-10 14:04:30 +08:00
zend_class_entry * ce ;
2005-09-09 14:48:49 +08:00
int use_autoload = ( fetch_type & ZEND_FETCH_CLASS_NO_AUTOLOAD ) = = 0 ;
2007-10-03 18:33:02 +08:00
int silent = ( fetch_type & ZEND_FETCH_CLASS_SILENT ) ! = 0 ;
2003-08-03 16:21:08 +08:00
2007-10-03 18:33:02 +08:00
fetch_type & = ZEND_FETCH_CLASS_MASK ;
2007-11-03 03:40:39 +08:00
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 ;
2007-09-29 15:28:34 +08:00
case ZEND_FETCH_CLASS_STATIC :
2014-07-03 06:34:43 +08:00
if ( ! EG ( current_execute_data ) | | ! EG ( current_execute_data ) - > called_scope ) {
2007-09-29 15:28:34 +08:00
zend_error ( E_ERROR , " Cannot access static:: when no class scope is active " ) ;
}
2014-07-03 06:34:43 +08:00
return EG ( current_execute_data ) - > called_scope ;
2003-08-03 16:21:08 +08:00
case ZEND_FETCH_CLASS_AUTO : {
2014-07-28 21:39:43 +08:00
fetch_type = zend_get_class_fetch_type ( class_name ) ;
2003-08-03 16:21:08 +08:00
if ( fetch_type ! = ZEND_FETCH_CLASS_DEFAULT ) {
goto check_fetch_type ;
}
}
break ;
}
2014-02-10 14:04:30 +08:00
if ( ( ce = zend_lookup_class_ex ( class_name , NULL , use_autoload TSRMLS_CC ) ) = = NULL ) {
2005-09-09 14:48:49 +08:00
if ( use_autoload ) {
2008-09-15 18:19:53 +08:00
if ( ! silent & & ! EG ( exception ) ) {
2007-10-03 18:33:02 +08:00
if ( fetch_type = = ZEND_FETCH_CLASS_INTERFACE ) {
2014-02-10 14:04:30 +08:00
zend_error ( E_ERROR , " Interface '%s' not found " , class_name - > val ) ;
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-23 06:05:56 +08:00
} else if ( fetch_type = = ZEND_FETCH_CLASS_TRAIT ) {
2014-02-10 14:04:30 +08:00
zend_error ( E_ERROR , " Trait '%s' not found " , class_name - > val ) ;
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-23 06:05:56 +08:00
} else {
2014-02-10 14:04:30 +08:00
zend_error ( E_ERROR , " Class '%s' not found " , class_name - > val ) ;
2012-07-23 05:25:00 +08:00
}
2005-09-09 14:48:49 +08:00
}
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
}
2014-02-10 14:04:30 +08:00
return ce ;
2003-08-03 16:21:08 +08:00
}
2007-11-03 03:40:39 +08:00
/* }}} */
2004-02-03 20:17:09 +08:00
2014-04-17 19:40:45 +08:00
zend_class_entry * zend_fetch_class_by_name ( zend_string * class_name , const zval * key , int fetch_type TSRMLS_DC ) /* { { { */
2010-04-20 18:57:45 +08:00
{
2014-02-10 14:04:30 +08:00
zend_class_entry * ce ;
2010-04-20 18:57:45 +08:00
int use_autoload = ( fetch_type & ZEND_FETCH_CLASS_NO_AUTOLOAD ) = = 0 ;
2014-02-10 14:04:30 +08:00
if ( ( ce = zend_lookup_class_ex ( class_name , key , use_autoload TSRMLS_CC ) ) = = NULL ) {
2010-04-20 18:57:45 +08:00
if ( use_autoload ) {
if ( ( fetch_type & ZEND_FETCH_CLASS_SILENT ) = = 0 & & ! EG ( exception ) ) {
if ( ( fetch_type & ZEND_FETCH_CLASS_MASK ) = = ZEND_FETCH_CLASS_INTERFACE ) {
2014-02-10 14:04:30 +08:00
zend_error ( E_ERROR , " Interface '%s' not found " , class_name - > val ) ;
2010-04-23 16:56:03 +08:00
} else if ( ( fetch_type & ZEND_FETCH_CLASS_MASK ) = = ZEND_FETCH_CLASS_TRAIT ) {
2014-02-10 14:04:30 +08:00
zend_error ( E_ERROR , " Trait '%s' not found " , class_name - > val ) ;
2010-04-20 18:57:45 +08:00
} else {
2014-02-10 14:04:30 +08:00
zend_error ( E_ERROR , " Class '%s' not found " , class_name - > val ) ;
2012-07-23 05:25:00 +08:00
}
2010-04-20 18:57:45 +08:00
}
}
return NULL ;
}
2014-02-10 14:04:30 +08:00
return ce ;
2010-04-20 18:57:45 +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 ] ? " :: " : " " , \
2014-02-10 14:04:30 +08:00
ai . afn [ idx ] ? ai . afn [ idx ] - > common . function_name - > val : " " , \
2007-11-03 03:40:39 +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 {
2007-11-03 03:40:39 +08:00
zend_function * afn [ MAX_ABSTRACT_INFO_CNT + 1 ] ;
2004-02-05 00:30:15 +08:00
int cnt ;
2008-01-29 19:12:57 +08:00
int ctor ;
2004-02-05 00:30:15 +08:00
} zend_abstract_info ;
2014-06-17 01:11:52 +08:00
static void zend_verify_abstract_class_function ( zend_function * fn , zend_abstract_info * ai TSRMLS_DC ) /* { { { */
2004-02-05 00:30:15 +08:00
{
if ( fn - > common . fn_flags & ZEND_ACC_ABSTRACT ) {
if ( ai - > cnt < MAX_ABSTRACT_INFO_CNT ) {
ai - > afn [ ai - > cnt ] = fn ;
}
2008-01-29 19:12:57 +08:00
if ( fn - > common . fn_flags & ZEND_ACC_CTOR ) {
if ( ! ai - > ctor ) {
ai - > cnt + + ;
ai - > ctor = 1 ;
} else {
ai - > afn [ ai - > cnt ] = NULL ;
}
} else {
ai - > cnt + + ;
}
2004-02-05 00:30:15 +08:00
}
}
2007-11-03 03:40:39 +08:00
/* }}} */
2004-02-05 00:30:15 +08:00
2007-11-03 03:40:39 +08:00
void zend_verify_abstract_class ( zend_class_entry * ce TSRMLS_DC ) /* { { { */
2004-02-05 00:30:15 +08:00
{
2014-06-17 01:11:52 +08:00
zend_function * func ;
2004-02-05 00:30:15 +08:00
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 ) ) ;
2014-06-17 01:11:52 +08:00
ZEND_HASH_FOREACH_PTR ( & ce - > function_table , func ) {
zend_verify_abstract_class_function ( func , & ai TSRMLS_CC ) ;
} ZEND_HASH_FOREACH_END ( ) ;
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 " ) " ,
2014-02-10 14:04:30 +08:00
ce - > name - > val , 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
}
}
2007-11-03 03:40:39 +08:00
/* }}} */
2004-02-05 00:30:15 +08:00
2014-02-10 14:04:30 +08:00
ZEND_API int zend_delete_global_variable ( zend_string * name TSRMLS_DC ) /* { { { */
2004-10-05 03:54:35 +08:00
{
2014-03-26 22:07:31 +08:00
return zend_hash_del_ind ( & EG ( symbol_table ) . ht , name ) ;
2004-10-05 03:54:35 +08:00
}
2007-11-03 03:40:39 +08:00
/* }}} */
2004-02-05 00:30:15 +08:00
2014-07-04 22:03:45 +08:00
ZEND_API zend_array * zend_rebuild_symbol_table ( TSRMLS_D ) /* { { { */
2008-04-29 16:15:20 +08:00
{
2014-09-15 22:04:12 +08:00
int i ;
2008-09-17 23:11:28 +08:00
zend_execute_data * ex ;
2014-07-04 22:03:45 +08:00
zend_array * symbol_table ;
2008-04-29 16:15:20 +08:00
2014-07-04 22:03:45 +08:00
/* Search for last called user function */
ex = EG ( current_execute_data ) ;
while ( ex & & ( ! ex - > func | | ! ZEND_USER_CODE ( ex - > func - > common . type ) ) ) {
ex = ex - > prev_execute_data ;
}
if ( ! ex ) {
return NULL ;
}
if ( ex - > symbol_table ) {
return ex - > symbol_table ;
}
2008-09-17 23:11:28 +08:00
2014-07-04 22:03:45 +08:00
if ( EG ( symtable_cache_ptr ) > = EG ( symtable_cache ) ) {
/*printf("Cache hit! Reusing %x\n", symtable_cache[symtable_cache_ptr]);*/
symbol_table = ex - > symbol_table = * ( EG ( symtable_cache_ptr ) - - ) ;
} else {
symbol_table = ex - > symbol_table = emalloc ( sizeof ( zend_array ) ) ;
GC_REFCOUNT ( symbol_table ) = 0 ;
GC_TYPE_INFO ( symbol_table ) = IS_ARRAY ;
zend_hash_init ( & symbol_table - > ht , ex - > func - > op_array . last_var , NULL , ZVAL_PTR_DTOR , 0 ) ;
/*printf("Cache miss! Initialized %x\n", EG(active_symbol_table));*/
}
for ( i = 0 ; i < ex - > func - > op_array . last_var ; i + + ) {
zval zv ;
2014-06-27 03:51:14 +08:00
2014-07-04 22:03:45 +08:00
ZVAL_INDIRECT ( & zv , EX_VAR_NUM_2 ( ex , i ) ) ;
zend_hash_add_new ( & symbol_table - > ht ,
ex - > func - > op_array . vars [ i ] , & zv ) ;
2014-03-26 22:07:31 +08:00
}
2014-07-04 22:03:45 +08:00
return symbol_table ;
2014-03-26 22:07:31 +08:00
}
/* }}} */
2014-04-18 17:46:36 +08:00
ZEND_API void zend_attach_symbol_table ( zend_execute_data * execute_data ) /* { { { */
2014-03-26 22:07:31 +08:00
{
int i ;
2014-06-27 03:51:14 +08:00
zend_op_array * op_array = & execute_data - > func - > op_array ;
2014-04-18 17:46:36 +08:00
HashTable * ht = & execute_data - > symbol_table - > ht ;
2014-03-26 22:07:31 +08:00
/* copy real values from symbol table into CV slots and create
INDIRECT references to CV in symbol table */
for ( i = 0 ; i < op_array - > last_var ; i + + ) {
zval * zv = zend_hash_find ( ht , op_array - > vars [ i ] ) ;
if ( zv ) {
if ( Z_TYPE_P ( zv ) = = IS_INDIRECT ) {
zval * val = Z_INDIRECT_P ( zv ) ;
if ( Z_TYPE_P ( val ) = = IS_UNDEF ) {
ZVAL_UNDEF ( EX_VAR_NUM ( i ) ) ;
} else {
ZVAL_COPY_VALUE ( EX_VAR_NUM ( i ) , val ) ;
2008-04-29 16:15:20 +08:00
}
2014-03-26 22:07:31 +08:00
} else {
ZVAL_COPY_VALUE ( EX_VAR_NUM ( i ) , zv ) ;
2008-04-29 16:15:20 +08:00
}
2014-03-26 22:07:31 +08:00
} else {
ZVAL_UNDEF ( EX_VAR_NUM ( i ) ) ;
zv = zend_hash_update ( ht , op_array - > vars [ i ] , EX_VAR_NUM ( i ) ) ;
2008-04-29 16:15:20 +08:00
}
2014-03-26 22:07:31 +08:00
ZVAL_INDIRECT ( zv , EX_VAR_NUM ( i ) ) ;
2008-04-29 16:15:20 +08:00
}
}
/* }}} */
2014-04-18 17:46:36 +08:00
ZEND_API void zend_detach_symbol_table ( zend_execute_data * execute_data ) /* { { { */
2014-03-26 22:07:31 +08:00
{
int i ;
2014-06-27 03:51:14 +08:00
zend_op_array * op_array = & execute_data - > func - > op_array ;
2014-04-18 17:46:36 +08:00
HashTable * ht = & execute_data - > symbol_table - > ht ;
2014-03-26 22:07:31 +08:00
/* copy real values from CV slots into symbol table */
for ( i = 0 ; i < op_array - > last_var ; i + + ) {
2014-03-27 04:04:50 +08:00
if ( Z_TYPE_P ( EX_VAR_NUM ( i ) ) = = IS_UNDEF ) {
zend_hash_del ( ht , op_array - > vars [ i ] ) ;
} else {
zend_hash_update ( ht , op_array - > vars [ i ] , EX_VAR_NUM ( i ) ) ;
ZVAL_UNDEF ( EX_VAR_NUM ( i ) ) ;
}
2014-03-26 22:07:31 +08:00
}
}
/* }}} */
2014-04-02 02:36:17 +08:00
ZEND_API int zend_set_local_var ( zend_string * name , zval * value , int force TSRMLS_DC ) /* { { { */
{
2014-07-04 22:03:45 +08:00
zend_execute_data * execute_data = EG ( current_execute_data ) ;
while ( execute_data & & ( ! execute_data - > func | | ! ZEND_USER_CODE ( execute_data - > func - > common . type ) ) ) {
execute_data = execute_data - > prev_execute_data ;
}
if ( execute_data ) {
if ( ! execute_data - > symbol_table ) {
2014-08-26 01:24:55 +08:00
zend_ulong h = zend_string_hash_val ( name ) ;
2014-07-04 22:03:45 +08:00
zend_op_array * op_array = & execute_data - > func - > op_array ;
int i ;
2014-07-03 02:01:25 +08:00
2014-04-02 02:36:17 +08:00
for ( i = 0 ; i < op_array - > last_var ; i + + ) {
if ( op_array - > vars [ i ] - > h = = h & &
op_array - > vars [ i ] - > len = = name - > len & &
memcmp ( op_array - > vars [ i ] - > val , name - > val , name - > len ) = = 0 ) {
ZVAL_COPY_VALUE ( EX_VAR_NUM ( i ) , value ) ;
return SUCCESS ;
}
}
2014-07-04 22:03:45 +08:00
if ( force ) {
zend_array * symbol_table = zend_rebuild_symbol_table ( TSRMLS_C ) ;
if ( symbol_table ) {
return zend_hash_update ( & symbol_table - > ht , name , value ) ? SUCCESS : FAILURE ; ;
}
2014-04-02 02:36:17 +08:00
}
} else {
2014-07-04 22:03:45 +08:00
return ( zend_hash_update_ind ( & execute_data - > symbol_table - > ht , name , value ) ! = NULL ) ? SUCCESS : FAILURE ;
2014-04-02 02:36:17 +08:00
}
}
2014-07-04 22:03:45 +08:00
return FAILURE ;
2014-04-02 02:36:17 +08:00
}
/* }}} */
ZEND_API int zend_set_local_var_str ( const char * name , int len , zval * value , int force TSRMLS_DC ) /* { { { */
2014-03-26 22:07:31 +08:00
{
2014-07-04 22:03:45 +08:00
zend_execute_data * execute_data = EG ( current_execute_data ) ;
while ( execute_data & & ( ! execute_data - > func | | ! ZEND_USER_CODE ( execute_data - > func - > common . type ) ) ) {
execute_data = execute_data - > prev_execute_data ;
}
if ( execute_data ) {
if ( ! execute_data - > symbol_table ) {
zend_ulong h = zend_hash_func ( name , len ) ;
zend_op_array * op_array = & execute_data - > func - > op_array ;
int i ;
2014-07-03 02:01:25 +08:00
2014-03-26 22:07:31 +08:00
for ( i = 0 ; i < op_array - > last_var ; i + + ) {
if ( op_array - > vars [ i ] - > h = = h & &
op_array - > vars [ i ] - > len = = len & &
memcmp ( op_array - > vars [ i ] - > val , name , len ) = = 0 ) {
2014-08-19 00:12:50 +08:00
zval_ptr_dtor ( EX_VAR_NUM ( i ) ) ;
2014-03-26 22:07:31 +08:00
ZVAL_COPY_VALUE ( EX_VAR_NUM ( i ) , value ) ;
return SUCCESS ;
}
}
2014-07-04 22:03:45 +08:00
if ( force ) {
zend_array * symbol_table = zend_rebuild_symbol_table ( TSRMLS_C ) ;
if ( symbol_table ) {
return zend_hash_str_update ( & symbol_table - > ht , name , len , value ) ? SUCCESS : FAILURE ; ;
}
2014-03-26 22:07:31 +08:00
}
} else {
2014-07-04 22:03:45 +08:00
return ( zend_hash_str_update_ind ( & execute_data - > symbol_table - > ht , name , len , value ) ! = NULL ) ? SUCCESS : FAILURE ;
2014-03-26 22:07:31 +08:00
}
}
2014-07-04 22:03:45 +08:00
return FAILURE ;
2014-03-26 22:07:31 +08:00
}
/* }}} */
2003-02-01 09:49:15 +08:00
/*
* Local variables :
* tab - width : 4
* c - basic - offset : 4
* indent - tabs - mode : t
* End :
*/