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 , |
2013-01-28 10:02:51 +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
2004-12-30 23:18:24 +08:00
# include <zend_language_parser.h>
1999-04-08 02:10:10 +08:00
# include "zend.h"
# include "zend_compile.h"
2003-04-11 01:02:31 +08:00
# include "zend_constants.h"
1999-04-08 02:10:10 +08:00
# include "zend_llist.h"
# include "zend_API.h"
2007-02-24 10:17:47 +08:00
# include "zend_exceptions.h"
2013-10-17 15:43:52 +08:00
# include "zend_virtual_cwd.h"
2008-06-29 16:21:35 +08:00
# include "zend_multibyte.h"
2011-01-20 05:40:15 +08:00
# include "zend_language_scanner.h"
2008-06-29 16:21:35 +08:00
2010-04-20 18:57:45 +08:00
# define CONSTANT_EX(op_array, op) \
2014-04-17 19:40:45 +08:00
( op_array ) - > literals [ op ]
2010-04-20 18:57:45 +08:00
# define CONSTANT(op) \
CONSTANT_EX ( CG ( active_op_array ) , op )
# define SET_NODE(target, src) do { \
target # # _type = ( src ) - > op_type ; \
if ( ( src ) - > op_type = = IS_CONST ) { \
2010-09-15 15:38:52 +08:00
target . constant = zend_add_literal ( CG ( active_op_array ) , & ( src ) - > u . constant TSRMLS_CC ) ; \
2010-04-20 18:57:45 +08:00
} else { \
target = ( src ) - > u . op ; \
} \
} while ( 0 )
# define GET_NODE(target, src) do { \
( target ) - > op_type = src # # _type ; \
if ( ( target ) - > op_type = = IS_CONST ) { \
( target ) - > u . constant = CONSTANT ( src . constant ) ; \
} else { \
( target ) - > u . op = src ; \
( target ) - > EA = 0 ; \
} \
} while ( 0 )
# define COPY_NODE(target, src) do { \
target # # _type = src # # _type ; \
target = src ; \
} while ( 0 )
2010-05-24 22:11:39 +08:00
# define GET_CACHE_SLOT(literal) do { \
2014-04-17 19:40:45 +08:00
Z_CACHE_SLOT ( CG ( active_op_array ) - > literals [ literal ] ) = CG ( active_op_array ) - > last_cache_slot + + ; \
2011-07-11 15:10:30 +08:00
if ( ( CG ( active_op_array ) - > fn_flags & ZEND_ACC_INTERACTIVE ) & & CG ( active_op_array ) - > run_time_cache ) { \
CG ( active_op_array ) - > run_time_cache = erealloc ( CG ( active_op_array ) - > run_time_cache , CG ( active_op_array ) - > last_cache_slot * sizeof ( void * ) ) ; \
CG ( active_op_array ) - > run_time_cache [ CG ( active_op_array ) - > last_cache_slot - 1 ] = NULL ; \
} \
2010-05-24 22:11:39 +08:00
} while ( 0 )
# define POLYMORPHIC_CACHE_SLOT_SIZE 2
# define GET_POLYMORPHIC_CACHE_SLOT(literal) do { \
2014-04-17 19:40:45 +08:00
Z_CACHE_SLOT ( CG ( active_op_array ) - > literals [ literal ] ) = CG ( active_op_array ) - > last_cache_slot ; \
2010-05-24 22:11:39 +08:00
CG ( active_op_array ) - > last_cache_slot + = POLYMORPHIC_CACHE_SLOT_SIZE ; \
2011-07-11 15:10:30 +08:00
if ( ( CG ( active_op_array ) - > fn_flags & ZEND_ACC_INTERACTIVE ) & & CG ( active_op_array ) - > run_time_cache ) { \
CG ( active_op_array ) - > run_time_cache = erealloc ( CG ( active_op_array ) - > run_time_cache , CG ( active_op_array ) - > last_cache_slot * sizeof ( void * ) ) ; \
CG ( active_op_array ) - > run_time_cache [ CG ( active_op_array ) - > last_cache_slot - 1 ] = NULL ; \
CG ( active_op_array ) - > run_time_cache [ CG ( active_op_array ) - > last_cache_slot - 2 ] = NULL ; \
} \
2010-05-24 22:11:39 +08:00
} while ( 0 )
# define FREE_POLYMORPHIC_CACHE_SLOT(literal) do { \
2014-04-17 19:40:45 +08:00
if ( Z_CACHE_SLOT ( CG ( active_op_array ) - > literals [ literal ] ) ! = - 1 & & \
Z_CACHE_SLOT ( CG ( active_op_array ) - > literals [ literal ] ) = = \
2010-05-24 22:11:39 +08:00
CG ( active_op_array ) - > last_cache_slot - POLYMORPHIC_CACHE_SLOT_SIZE ) { \
2014-04-17 19:40:45 +08:00
Z_CACHE_SLOT ( CG ( active_op_array ) - > literals [ literal ] ) = - 1 ; \
2010-05-24 22:11:39 +08:00
CG ( active_op_array ) - > last_cache_slot - = POLYMORPHIC_CACHE_SLOT_SIZE ; \
} \
} while ( 0 )
2001-07-28 18:51:54 +08:00
ZEND_API zend_op_array * ( * zend_compile_file ) ( zend_file_handle * file_handle , int type TSRMLS_DC ) ;
2006-06-13 20:57:48 +08:00
ZEND_API zend_op_array * ( * zend_compile_string ) ( zval * source_string , char * filename TSRMLS_DC ) ;
1999-04-08 02:10:10 +08:00
# ifndef ZTS
ZEND_API zend_compiler_globals compiler_globals ;
ZEND_API zend_executor_globals executor_globals ;
# endif
2014-02-26 06:39:50 +08:00
static void zend_push_function_call_entry ( zend_function * fbc TSRMLS_DC ) /* { { { */
{
zend_function_call_entry fcall = { fbc } ;
2014-05-01 02:28:02 +08:00
zend_stack_push ( & CG ( function_call_stack ) , & fcall ) ;
2014-02-26 06:39:50 +08:00
}
/* }}} */
2014-05-27 01:29:35 +08:00
static zend_property_info * zend_duplicate_property_info ( zend_property_info * property_info ) /* { { { */
2003-08-24 03:37:39 +08:00
{
2014-05-27 01:29:35 +08:00
zend_property_info * new_property_info = emalloc ( sizeof ( zend_property_info ) ) ;
memcpy ( new_property_info , property_info , sizeof ( zend_property_info ) ) ;
STR_ADDREF ( new_property_info - > name ) ;
if ( new_property_info - > doc_comment ) {
STR_ADDREF ( new_property_info - > doc_comment ) ;
2005-04-25 01:32:05 +08:00
}
2014-05-27 01:29:35 +08:00
return new_property_info ;
2003-08-24 03:37:39 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2003-08-24 03:37:39 +08:00
2014-05-27 01:29:35 +08:00
static zend_property_info * zend_duplicate_property_info_internal ( zend_property_info * property_info ) /* { { { */
2003-08-24 03:37:39 +08:00
{
2014-05-27 01:29:35 +08:00
zend_property_info * new_property_info = pemalloc ( sizeof ( zend_property_info ) , 1 ) ;
memcpy ( new_property_info , property_info , sizeof ( zend_property_info ) ) ;
STR_ADDREF ( new_property_info - > name ) ;
return new_property_info ;
2014-02-17 15:50:32 +08:00
}
/* }}} */
static void zend_destroy_property_info ( zval * zv ) /* { { { */
2003-08-24 03:37:39 +08:00
{
2014-02-17 15:50:32 +08:00
zend_property_info * property_info = Z_PTR_P ( zv ) ;
2014-02-10 14:04:30 +08:00
STR_RELEASE ( property_info - > name ) ;
2005-04-20 06:04:59 +08:00
if ( property_info - > doc_comment ) {
2014-02-10 14:04:30 +08:00
STR_RELEASE ( property_info - > doc_comment ) ;
2005-04-20 06:04:59 +08:00
}
2014-02-17 21:59:18 +08:00
efree ( property_info ) ;
2003-08-24 03:37:39 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2003-08-24 03:37:39 +08:00
2014-02-17 15:50:32 +08:00
static void zend_destroy_property_info_internal ( zval * zv ) /* { { { */
2003-08-24 03:37:39 +08:00
{
2014-02-17 15:50:32 +08:00
zend_property_info * property_info = Z_PTR_P ( zv ) ;
2014-02-10 14:04:30 +08:00
STR_RELEASE ( property_info - > name ) ;
2014-02-17 21:59:18 +08:00
free ( property_info ) ;
2003-08-24 03:37:39 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2003-08-24 03:37:39 +08:00
2009-07-27 22:11:53 +08:00
static void build_runtime_defined_function_key ( zval * result , const char * name , int name_length TSRMLS_DC ) /* { { { */
1999-09-03 05:06:05 +08:00
{
2004-01-12 03:27:13 +08:00
char char_pos_buf [ 32 ] ;
uint char_pos_len ;
2011-09-13 21:29:35 +08:00
const char * filename ;
1999-09-03 05:06:05 +08:00
2008-03-17 05:06:55 +08:00
char_pos_len = zend_sprintf ( char_pos_buf , " %p " , LANG_SCNG ( yy_text ) ) ;
2000-08-10 03:22:35 +08:00
if ( CG ( active_op_array ) - > filename ) {
2014-02-10 14:04:30 +08:00
filename = CG ( active_op_array ) - > filename - > val ;
1999-09-03 05:06:05 +08:00
} else {
filename = " - " ;
}
2004-01-12 03:27:13 +08:00
/* NULL, name length, filename length, last accepting char position length */
2014-04-03 19:26:23 +08:00
ZVAL_NEW_STR ( result , STR_ALLOC ( 1 + name_length + strlen ( filename ) + char_pos_len , 0 ) ) ;
2010-11-24 13:41:23 +08:00
2008-06-29 16:21:35 +08:00
/* must be binary safe */
2014-02-18 05:41:23 +08:00
Z_STRVAL_P ( result ) [ 0 ] = ' \0 ' ;
2013-09-13 21:07:47 +08:00
sprintf ( Z_STRVAL_P ( result ) + 1 , " %s%s%s " , name , filename , char_pos_buf ) ;
1999-09-03 05:06:05 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-09-03 05:06:05 +08:00
2009-07-27 22:11:53 +08:00
static void init_compiler_declarables ( TSRMLS_D ) /* { { { */
2000-01-25 03:00:30 +08:00
{
2014-02-10 14:04:30 +08:00
ZVAL_LONG ( & CG ( declarables ) . ticks , 0 ) ;
2000-01-25 03:00:30 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2000-01-25 03:00:30 +08:00
2010-09-15 15:38:52 +08:00
void zend_init_compiler_context ( TSRMLS_D ) /* { { { */
{
CG ( context ) . opcodes_size = ( CG ( active_op_array ) - > fn_flags & ZEND_ACC_INTERACTIVE ) ? INITIAL_INTERACTIVE_OP_ARRAY_SIZE : INITIAL_OP_ARRAY_SIZE ;
CG ( context ) . vars_size = 0 ;
CG ( context ) . literals_size = 0 ;
CG ( context ) . current_brk_cont = - 1 ;
CG ( context ) . backpatch_count = 0 ;
2012-11-30 17:39:23 +08:00
CG ( context ) . nested_calls = 0 ;
CG ( context ) . used_stack = 0 ;
2012-12-13 06:48:51 +08:00
CG ( context ) . in_finally = 0 ;
2010-09-15 15:38:52 +08:00
CG ( context ) . labels = NULL ;
}
/* }}} */
2000-01-25 03:00:30 +08:00
2009-07-27 22:11:53 +08:00
void zend_init_compiler_data_structures ( TSRMLS_D ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2014-05-01 02:28:02 +08:00
zend_stack_init ( & CG ( bp_stack ) , sizeof ( zend_llist ) ) ;
zend_stack_init ( & CG ( function_call_stack ) , sizeof ( zend_function_call_entry ) ) ;
zend_stack_init ( & CG ( switch_cond_stack ) , sizeof ( zend_switch_entry ) ) ;
zend_stack_init ( & CG ( foreach_copy_stack ) , sizeof ( zend_op ) ) ;
zend_stack_init ( & CG ( object_stack ) , sizeof ( znode ) ) ;
zend_stack_init ( & CG ( declare_stack ) , sizeof ( zend_declarables ) ) ;
1999-04-08 02:10:10 +08:00
CG ( active_class_entry ) = NULL ;
zend_llist_init ( & CG ( list_llist ) , sizeof ( list_llist_element ) , NULL , 0 ) ;
zend_llist_init ( & CG ( dimension_llist ) , sizeof ( int ) , NULL , 0 ) ;
2014-05-01 02:28:02 +08:00
zend_stack_init ( & CG ( list_stack ) , sizeof ( zend_llist ) ) ;
2000-02-04 22:45:58 +08:00
CG ( in_compilation ) = 0 ;
2003-01-06 00:09:59 +08:00
CG ( start_lineno ) = 0 ;
2014-02-10 14:04:30 +08:00
ZVAL_UNDEF ( & CG ( current_namespace ) ) ;
2008-11-25 17:56:32 +08:00
CG ( in_namespace ) = 0 ;
CG ( has_bracketed_namespaces ) = 0 ;
2007-09-29 03:52:53 +08:00
CG ( current_import ) = NULL ;
2013-07-17 02:39:33 +08:00
CG ( current_import_function ) = NULL ;
2013-07-24 02:21:48 +08:00
CG ( current_import_const ) = NULL ;
2014-04-21 22:25:34 +08:00
zend_hash_init ( & CG ( const_filenames ) , 8 , NULL , NULL , 0 ) ;
2001-07-28 18:51:54 +08:00
init_compiler_declarables ( TSRMLS_C ) ;
2014-05-01 02:28:02 +08:00
zend_stack_init ( & CG ( context_stack ) , sizeof ( CG ( context ) ) ) ;
2008-06-29 16:21:35 +08:00
2009-11-17 06:52:00 +08:00
CG ( encoding_declared ) = 0 ;
2008-03-17 05:06:55 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2008-03-17 05:06:55 +08:00
2009-07-27 22:11:53 +08:00
ZEND_API void file_handle_dtor ( zend_file_handle * fh ) /* { { { */
2008-03-17 05:06:55 +08:00
{
TSRMLS_FETCH ( ) ;
2003-08-11 13:24:42 +08:00
2008-03-17 05:06:55 +08:00
zend_file_handle_dtor ( fh TSRMLS_CC ) ;
2001-05-07 03:30:31 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2001-05-07 03:30:31 +08:00
2009-07-27 22:11:53 +08:00
void init_compiler ( TSRMLS_D ) /* { { { */
2001-05-07 03:30:31 +08:00
{
2006-05-02 23:49:26 +08:00
CG ( active_op_array ) = NULL ;
2012-11-14 21:45:10 +08:00
memset ( & CG ( context ) , 0 , sizeof ( CG ( context ) ) ) ;
2001-07-28 18:51:54 +08:00
zend_init_compiler_data_structures ( TSRMLS_C ) ;
2001-07-27 18:10:39 +08:00
zend_init_rsrc_list ( TSRMLS_C ) ;
2014-04-21 22:25:34 +08:00
zend_hash_init ( & CG ( filenames_table ) , 8 , NULL , free_string_zval , 0 ) ;
2008-03-17 05:06:55 +08:00
zend_llist_init ( & CG ( open_files ) , sizeof ( zend_file_handle ) , ( void ( * ) ( void * ) ) file_handle_dtor , 0 ) ;
2001-05-07 03:30:31 +08:00
CG ( unclean_shutdown ) = 0 ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void shutdown_compiler ( TSRMLS_D ) /* { { { */
1999-04-08 02:10:10 +08:00
{
zend_stack_destroy ( & CG ( bp_stack ) ) ;
zend_stack_destroy ( & CG ( function_call_stack ) ) ;
zend_stack_destroy ( & CG ( switch_cond_stack ) ) ;
1999-09-09 22:15:17 +08:00
zend_stack_destroy ( & CG ( foreach_copy_stack ) ) ;
1999-04-08 02:10:10 +08:00
zend_stack_destroy ( & CG ( object_stack ) ) ;
2000-01-25 03:00:30 +08:00
zend_stack_destroy ( & CG ( declare_stack ) ) ;
2001-07-16 23:48:31 +08:00
zend_stack_destroy ( & CG ( list_stack ) ) ;
2000-08-20 01:50:42 +08:00
zend_hash_destroy ( & CG ( filenames_table ) ) ;
2013-08-25 05:53:43 +08:00
zend_hash_destroy ( & CG ( const_filenames ) ) ;
2010-09-15 15:38:52 +08:00
zend_stack_destroy ( & CG ( context_stack ) ) ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-02-10 14:04:30 +08:00
ZEND_API zend_string * zend_set_compiled_filename ( zend_string * new_compiled_filename TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2014-02-10 14:04:30 +08:00
zend_string * p ;
1999-04-08 02:10:10 +08:00
2014-02-10 14:04:30 +08:00
p = zend_hash_find_ptr ( & CG ( filenames_table ) , new_compiled_filename ) ;
if ( p ! = NULL ) {
CG ( compiled_filename ) = p ;
return p ;
2000-08-20 01:50:42 +08:00
}
2014-02-10 14:04:30 +08:00
p = STR_COPY ( new_compiled_filename ) ;
zend_hash_update_ptr ( & CG ( filenames_table ) , new_compiled_filename , p ) ;
1999-04-08 02:10:10 +08:00
CG ( compiled_filename ) = p ;
1999-08-03 02:40:10 +08:00
return p ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-02-10 14:04:30 +08:00
ZEND_API void zend_restore_compiled_filename ( zend_string * original_compiled_filename TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
CG ( compiled_filename ) = original_compiled_filename ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-02-10 14:04:30 +08:00
ZEND_API zend_string * zend_get_compiled_filename ( TSRMLS_D ) /* { { { */
2000-02-04 22:45:58 +08:00
{
return CG ( compiled_filename ) ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
2000-02-04 22:45:58 +08:00
2009-07-27 22:11:53 +08:00
ZEND_API int zend_get_compiled_lineno ( TSRMLS_D ) /* { { { */
2000-02-04 22:45:58 +08:00
{
return CG ( zend_lineno ) ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
2000-02-04 22:45:58 +08:00
2009-07-27 22:11:53 +08:00
ZEND_API zend_bool zend_is_compiling ( TSRMLS_D ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2000-02-04 22:45:58 +08:00
return CG ( in_compilation ) ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
static zend_uint get_temporary_variable ( zend_op_array * op_array ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2014-02-18 05:41:23 +08:00
return ( zend_uint ) op_array - > T + + ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-02-10 14:04:30 +08:00
static int lookup_cv ( zend_op_array * op_array , zend_string * name TSRMLS_DC ) /* { { { */ {
2004-10-05 03:54:35 +08:00
int i = 0 ;
2014-02-10 14:04:30 +08:00
ulong hash_value = STR_HASH_VAL ( name ) ;
2004-10-05 03:54:35 +08:00
while ( i < op_array - > last_var ) {
2014-02-10 14:04:30 +08:00
if ( op_array - > vars [ i ] - > val = = name - > val | |
( op_array - > vars [ i ] - > h = = hash_value & &
op_array - > vars [ i ] - > len = = name - > len & &
memcmp ( op_array - > vars [ i ] - > val , name - > val , name - > len ) = = 0 ) ) {
STR_RELEASE ( name ) ;
2014-03-27 20:00:25 +08:00
return ( int ) EX_VAR_NUM_2 ( NULL , i ) ;
2004-10-05 03:54:35 +08:00
}
i + + ;
}
i = op_array - > last_var ;
op_array - > last_var + + ;
2010-09-15 15:38:52 +08:00
if ( op_array - > last_var > CG ( context ) . vars_size ) {
CG ( context ) . vars_size + = 16 ; /* FIXME */
2014-02-10 14:04:30 +08:00
op_array - > vars = erealloc ( op_array - > vars , CG ( context ) . vars_size * sizeof ( zend_string * ) ) ;
2004-10-05 03:54:35 +08:00
}
2014-02-10 14:04:30 +08:00
op_array - > vars [ i ] = zend_new_interned_string ( name TSRMLS_CC ) ;
2014-03-27 20:00:25 +08:00
return ( int ) EX_VAR_NUM_2 ( NULL , i ) ;
2004-10-05 03:54:35 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2004-10-05 03:54:35 +08:00
2010-04-20 18:57:45 +08:00
void zend_del_literal ( zend_op_array * op_array , int n ) /* { { { */
{
zval_dtor ( & CONSTANT_EX ( op_array , n ) ) ;
if ( n + 1 = = op_array - > last_literal ) {
op_array - > last_literal - - ;
} else {
2014-02-10 14:04:30 +08:00
ZVAL_UNDEF ( & CONSTANT_EX ( op_array , n ) ) ;
2010-04-20 18:57:45 +08:00
}
}
/* }}} */
1999-04-08 02:10:10 +08:00
2011-08-15 17:54:06 +08:00
/* Common part of zend_add_literal and zend_append_individual_literal */
2014-02-18 05:41:23 +08:00
static inline void zend_insert_literal ( zend_op_array * op_array , zval * zv , int literal_position TSRMLS_DC ) /* { { { */
2011-08-15 17:54:06 +08:00
{
if ( Z_TYPE_P ( zv ) = = IS_STRING | | Z_TYPE_P ( zv ) = = IS_CONSTANT ) {
2014-02-10 14:04:30 +08:00
STR_HASH_VAL ( Z_STR_P ( zv ) ) ;
2014-02-18 05:41:23 +08:00
Z_STR_P ( zv ) = zend_new_interned_string ( Z_STR_P ( zv ) TSRMLS_CC ) ;
2014-04-03 19:26:23 +08:00
if ( IS_INTERNED ( Z_STR_P ( zv ) ) ) {
Z_TYPE_FLAGS_P ( zv ) & = ~ ( IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE ) ;
}
2011-08-15 17:54:06 +08:00
}
2014-02-10 14:04:30 +08:00
ZVAL_COPY_VALUE ( & CONSTANT_EX ( op_array , literal_position ) , zv ) ;
2014-04-17 19:40:45 +08:00
Z_CACHE_SLOT ( op_array - > literals [ literal_position ] ) = - 1 ;
2011-08-15 17:54:06 +08:00
}
/* }}} */
/* Is used while compiling a function, using the context to keep track
of an approximate size to avoid to relocate to often .
Literals are truncated to actual size in the second compiler pass ( pass_two ( ) ) . */
2014-04-22 22:52:59 +08:00
int zend_add_literal ( zend_op_array * op_array , zval * zv TSRMLS_DC ) /* { { { */
2010-04-20 18:57:45 +08:00
{
int i = op_array - > last_literal ;
op_array - > last_literal + + ;
2010-09-15 15:38:52 +08:00
if ( i > = CG ( context ) . literals_size ) {
2011-08-15 17:54:06 +08:00
while ( i > = CG ( context ) . literals_size ) {
CG ( context ) . literals_size + = 16 ; /* FIXME */
}
2014-04-17 19:40:45 +08:00
op_array - > literals = ( zval * ) erealloc ( op_array - > literals , CG ( context ) . literals_size * sizeof ( zval ) ) ;
2010-04-20 18:57:45 +08:00
}
2011-08-15 17:54:06 +08:00
zend_insert_literal ( op_array , zv , i TSRMLS_CC ) ;
return i ;
}
/* }}} */
2010-04-20 19:05:54 +08:00
2014-04-22 22:52:59 +08:00
static int zend_add_func_name_literal ( zend_op_array * op_array , zval * zv TSRMLS_DC ) /* { { { */
2010-04-21 22:58:33 +08:00
{
int ret ;
2014-02-10 14:04:30 +08:00
zend_string * lc_name ;
2010-04-21 22:58:33 +08:00
zval c ;
2013-01-28 10:02:51 +08:00
if ( op_array - > last_literal > 0 & &
2014-04-17 19:40:45 +08:00
& op_array - > literals [ op_array - > last_literal - 1 ] = = zv & &
Z_CACHE_SLOT ( op_array - > literals [ op_array - > last_literal - 1 ] ) = = - 1 ) {
2010-04-21 22:58:33 +08:00
/* we already have function name as last literal (do nothing) */
ret = op_array - > last_literal - 1 ;
} else {
2010-09-15 15:38:52 +08:00
ret = zend_add_literal ( op_array , zv TSRMLS_CC ) ;
2010-04-21 22:58:33 +08:00
}
2013-01-28 10:02:51 +08:00
2014-02-10 14:04:30 +08:00
lc_name = STR_ALLOC ( Z_STRLEN_P ( zv ) , 0 ) ;
zend_str_tolower_copy ( lc_name - > val , Z_STRVAL_P ( zv ) , Z_STRLEN_P ( zv ) ) ;
2014-04-03 19:26:23 +08:00
ZVAL_NEW_STR ( & c , lc_name ) ;
2014-02-10 14:04:30 +08:00
zend_add_literal ( CG ( active_op_array ) , & c TSRMLS_CC ) ;
2010-04-21 22:58:33 +08:00
return ret ;
}
/* }}} */
2014-04-22 22:52:59 +08:00
static int zend_add_ns_func_name_literal ( zend_op_array * op_array , zval * zv TSRMLS_DC ) /* { { { */
2010-04-27 20:09:13 +08:00
{
int ret ;
2014-02-10 14:04:30 +08:00
zend_string * lc_name ;
2011-09-13 21:29:35 +08:00
const char * ns_separator ;
2010-04-27 20:09:13 +08:00
int lc_len ;
zval c ;
2013-01-28 10:02:51 +08:00
if ( op_array - > last_literal > 0 & &
2014-04-17 19:40:45 +08:00
& op_array - > literals [ op_array - > last_literal - 1 ] = = zv & &
Z_CACHE_SLOT ( op_array - > literals [ op_array - > last_literal - 1 ] ) = = - 1 ) {
2010-04-27 20:09:13 +08:00
/* we already have function name as last literal (do nothing) */
ret = op_array - > last_literal - 1 ;
} else {
2010-09-15 15:38:52 +08:00
ret = zend_add_literal ( op_array , zv TSRMLS_CC ) ;
2010-04-27 20:09:13 +08:00
}
2014-02-10 14:04:30 +08:00
lc_name = STR_ALLOC ( Z_STRLEN_P ( zv ) , 0 ) ;
zend_str_tolower_copy ( lc_name - > val , Z_STRVAL_P ( zv ) , Z_STRLEN_P ( zv ) ) ;
2014-04-03 19:26:23 +08:00
ZVAL_NEW_STR ( & c , lc_name ) ;
2014-02-10 14:04:30 +08:00
zend_add_literal ( CG ( active_op_array ) , & c TSRMLS_CC ) ;
2010-04-27 20:09:13 +08:00
2013-08-22 09:24:59 +08:00
ns_separator = ( const char * ) zend_memrchr ( Z_STRVAL_P ( zv ) , ' \\ ' , Z_STRLEN_P ( zv ) ) ;
2013-08-24 05:39:42 +08:00
if ( ns_separator ! = NULL ) {
2013-08-22 09:24:59 +08:00
ns_separator + = 1 ;
lc_len = Z_STRLEN_P ( zv ) - ( ns_separator - Z_STRVAL_P ( zv ) ) ;
2014-02-10 14:04:30 +08:00
lc_name = STR_ALLOC ( lc_len , 0 ) ;
zend_str_tolower_copy ( lc_name - > val , ns_separator , lc_len ) ;
2014-04-03 19:26:23 +08:00
ZVAL_NEW_STR ( & c , lc_name ) ;
2014-02-10 14:04:30 +08:00
zend_add_literal ( CG ( active_op_array ) , & c TSRMLS_CC ) ;
2013-08-22 09:24:59 +08:00
}
2010-04-27 20:09:13 +08:00
return ret ;
}
/* }}} */
2010-04-21 22:58:33 +08:00
2014-04-22 22:52:59 +08:00
static int zend_add_class_name_literal ( zend_op_array * op_array , zval * zv TSRMLS_DC ) /* { { { */
2010-04-21 22:58:33 +08:00
{
int ret ;
2014-02-10 14:04:30 +08:00
zend_string * lc_name ;
2010-04-21 22:58:33 +08:00
zval c ;
2013-01-28 10:02:51 +08:00
if ( op_array - > last_literal > 0 & &
2014-04-17 19:40:45 +08:00
& op_array - > literals [ op_array - > last_literal - 1 ] = = zv & &
Z_CACHE_SLOT ( op_array - > literals [ op_array - > last_literal - 1 ] ) = = - 1 ) {
2010-04-21 22:58:33 +08:00
/* we already have function name as last literal (do nothing) */
ret = op_array - > last_literal - 1 ;
} else {
2010-09-15 15:38:52 +08:00
ret = zend_add_literal ( op_array , zv TSRMLS_CC ) ;
2010-04-21 22:58:33 +08:00
}
if ( Z_STRVAL_P ( zv ) [ 0 ] = = ' \\ ' ) {
2014-02-10 14:04:30 +08:00
lc_name = STR_ALLOC ( Z_STRLEN_P ( zv ) - 1 , 0 ) ;
zend_str_tolower_copy ( lc_name - > val , Z_STRVAL_P ( zv ) + 1 , Z_STRLEN_P ( zv ) - 1 ) ;
2010-04-21 22:58:33 +08:00
} else {
2014-02-10 14:04:30 +08:00
lc_name = STR_ALLOC ( Z_STRLEN_P ( zv ) , 0 ) ;
zend_str_tolower_copy ( lc_name - > val , Z_STRVAL_P ( zv ) , Z_STRLEN_P ( zv ) ) ;
2010-04-21 22:58:33 +08:00
}
2014-04-03 19:26:23 +08:00
ZVAL_NEW_STR ( & c , lc_name ) ;
2014-02-10 14:04:30 +08:00
zend_add_literal ( CG ( active_op_array ) , & c TSRMLS_CC ) ;
2010-04-21 22:58:33 +08:00
2010-05-24 22:11:39 +08:00
GET_CACHE_SLOT ( ret ) ;
2010-04-21 22:58:33 +08:00
return ret ;
}
/* }}} */
2014-04-22 22:52:59 +08:00
static int zend_add_const_name_literal ( zend_op_array * op_array , zval * zv , int unqualified TSRMLS_DC ) /* { { { */
2010-04-22 23:03:17 +08:00
{
2014-02-10 14:04:30 +08:00
int ret ;
char * name ;
zend_string * tmp_name ;
2011-09-13 21:29:35 +08:00
const char * ns_separator ;
2010-04-22 23:03:17 +08:00
int name_len , ns_len ;
zval c ;
2013-01-28 10:02:51 +08:00
if ( op_array - > last_literal > 0 & &
2014-04-17 19:40:45 +08:00
& op_array - > literals [ op_array - > last_literal - 1 ] = = zv & &
Z_CACHE_SLOT ( op_array - > literals [ op_array - > last_literal - 1 ] ) = = - 1 ) {
2010-04-22 23:03:17 +08:00
/* we already have function name as last literal (do nothing) */
ret = op_array - > last_literal - 1 ;
} else {
2010-09-15 15:38:52 +08:00
ret = zend_add_literal ( op_array , zv TSRMLS_CC ) ;
2010-04-22 23:03:17 +08:00
}
2013-01-28 10:02:51 +08:00
/* skip leading '\\' */
2010-04-22 23:03:17 +08:00
if ( Z_STRVAL_P ( zv ) [ 0 ] = = ' \\ ' ) {
name_len = Z_STRLEN_P ( zv ) - 1 ;
name = Z_STRVAL_P ( zv ) + 1 ;
} else {
name_len = Z_STRLEN_P ( zv ) ;
name = Z_STRVAL_P ( zv ) ;
}
ns_separator = zend_memrchr ( name , ' \\ ' , name_len ) ;
if ( ns_separator ) {
ns_len = ns_separator - name ;
} else {
ns_len = 0 ;
}
if ( ns_len ) {
/* lowercased namespace name & original constant name */
2014-02-10 14:04:30 +08:00
tmp_name = STR_INIT ( name , name_len , 0 ) ;
zend_str_tolower ( tmp_name - > val , ns_len ) ;
2014-04-03 19:26:23 +08:00
ZVAL_NEW_STR ( & c , tmp_name ) ;
2014-02-10 14:04:30 +08:00
zend_add_literal ( CG ( active_op_array ) , & c TSRMLS_CC ) ;
2010-04-22 23:03:17 +08:00
/* lowercased namespace name & lowercased constant name */
2014-02-10 14:04:30 +08:00
tmp_name = STR_ALLOC ( name_len , 0 ) ;
zend_str_tolower_copy ( tmp_name - > val , name , name_len ) ;
2014-04-03 19:26:23 +08:00
ZVAL_NEW_STR ( & c , tmp_name ) ;
2014-02-10 14:04:30 +08:00
zend_add_literal ( CG ( active_op_array ) , & c TSRMLS_CC ) ;
2010-04-22 23:03:17 +08:00
}
if ( ns_len ) {
if ( ! unqualified ) {
return ret ;
}
ns_len + + ;
name + = ns_len ;
name_len - = ns_len ;
}
/* original constant name */
2014-02-10 14:04:30 +08:00
tmp_name = STR_INIT ( name , name_len , 0 ) ;
2014-04-03 19:26:23 +08:00
ZVAL_NEW_STR ( & c , tmp_name ) ;
2014-02-10 14:04:30 +08:00
zend_add_literal ( CG ( active_op_array ) , & c TSRMLS_CC ) ;
2010-04-22 23:03:17 +08:00
/* lowercased constant name */
2014-02-10 14:04:30 +08:00
tmp_name = STR_ALLOC ( name_len , 0 ) ;
zend_str_tolower_copy ( tmp_name - > val , name , name_len ) ;
2014-04-03 19:26:23 +08:00
ZVAL_NEW_STR ( & c , tmp_name ) ;
2014-02-10 14:04:30 +08:00
zend_add_literal ( CG ( active_op_array ) , & c TSRMLS_CC ) ;
2010-04-22 23:03:17 +08:00
return ret ;
}
/* }}} */
2014-02-10 14:04:30 +08:00
# define LITERAL_STR(op, str) do { \
2010-04-20 18:57:45 +08:00
zval _c ; \
2014-02-10 14:04:30 +08:00
ZVAL_STR ( & _c , str ) ; \
op . constant = zend_add_literal ( CG ( active_op_array ) , & _c TSRMLS_CC ) ; \
} while ( 0 )
# define LITERAL_STRINGL(op, str, len) do { \
zval _c ; \
ZVAL_STRINGL ( & _c , str , len ) ; \
2010-09-15 15:38:52 +08:00
op . constant = zend_add_literal ( CG ( active_op_array ) , & _c TSRMLS_CC ) ; \
2010-04-20 18:57:45 +08:00
} while ( 0 )
# define LITERAL_LONG(op, val) do { \
zval _c ; \
ZVAL_LONG ( & _c , val ) ; \
2010-09-15 15:38:52 +08:00
op . constant = zend_add_literal ( CG ( active_op_array ) , & _c TSRMLS_CC ) ; \
2010-04-20 18:57:45 +08:00
} while ( 0 )
# define LITERAL_LONG_EX(op_array, op, val) do { \
zval _c ; \
ZVAL_LONG ( & _c , val ) ; \
2010-09-15 15:38:52 +08:00
op . constant = zend_add_literal ( op_array , & _c TSRMLS_CC ) ; \
2010-04-20 18:57:45 +08:00
} while ( 0 )
# define LITERAL_NULL(op) do { \
zval _c ; \
2014-02-10 14:04:30 +08:00
ZVAL_NULL ( & _c ) ; \
2010-09-15 15:38:52 +08:00
op . constant = zend_add_literal ( CG ( active_op_array ) , & _c TSRMLS_CC ) ; \
2010-04-20 18:57:45 +08:00
} while ( 0 )
2010-04-21 22:58:33 +08:00
2010-08-25 17:14:36 +08:00
static inline zend_bool zend_is_function_or_method_call ( const znode * variable ) /* { { { */
{
zend_uint type = variable - > EA ;
return ( ( type & ZEND_PARSED_METHOD_CALL ) | | ( type = = ZEND_PARSED_FUNCTION_CALL ) ) ;
}
/* }}} */
2014-04-22 22:52:59 +08:00
void zend_do_binary_op ( zend_uchar op , znode * result , znode * op1 , znode * op2 TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2001-07-28 18:51:54 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
opline - > opcode = op ;
2010-04-20 18:57:45 +08:00
opline - > result_type = IS_TMP_VAR ;
opline - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
SET_NODE ( opline - > op1 , op1 ) ;
SET_NODE ( opline - > op2 , op2 ) ;
GET_NODE ( result , opline - > result ) ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_unary_op ( zend_uchar op , znode * result , znode * op1 TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2001-07-28 18:51:54 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
opline - > opcode = op ;
2010-04-20 18:57:45 +08:00
opline - > result_type = IS_TMP_VAR ;
opline - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
SET_NODE ( opline - > op1 , op1 ) ;
GET_NODE ( result , opline - > result ) ;
1999-04-08 02:10:10 +08:00
SET_UNUSED ( opline - > op2 ) ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2010-04-20 18:57:45 +08:00
# define MAKE_NOP(opline) { opline->opcode = ZEND_NOP; memset(&opline->result,0,sizeof(opline->result)); memset(&opline->op1,0,sizeof(opline->op1)); memset(&opline->op2,0,sizeof(opline->op2)); opline->result_type=opline->op1_type=opline->op2_type=IS_UNUSED; }
2002-03-10 21:42:37 +08:00
2014-04-22 22:52:59 +08:00
static void zend_do_op_data ( zend_op * data_op , znode * value TSRMLS_DC ) /* { { { */
2003-01-27 23:13:01 +08:00
{
data_op - > opcode = ZEND_OP_DATA ;
2010-04-20 18:57:45 +08:00
SET_NODE ( data_op - > op1 , value ) ;
2003-01-27 23:13:01 +08:00
SET_UNUSED ( data_op - > op2 ) ;
2002-03-10 21:42:37 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_binary_assign_op ( zend_uchar op , znode * result , znode * op1 , znode * op2 TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2005-06-08 23:01:35 +08:00
int last_op_number = get_next_op_number ( CG ( active_op_array ) ) ;
2001-07-28 18:51:54 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
2003-07-31 01:40:54 +08:00
2005-06-08 23:01:35 +08:00
if ( last_op_number > 0 ) {
zend_op * last_op = & CG ( active_op_array ) - > opcodes [ last_op_number - 1 ] ;
2006-05-10 07:53:23 +08:00
2005-06-08 23:01:35 +08:00
switch ( last_op - > opcode ) {
case ZEND_FETCH_OBJ_RW :
last_op - > opcode = op ;
last_op - > extended_value = ZEND_ASSIGN_OBJ ;
zend_do_op_data ( opline , op2 TSRMLS_CC ) ;
SET_UNUSED ( opline - > result ) ;
2010-04-20 18:57:45 +08:00
GET_NODE ( result , last_op - > result ) ;
2005-06-08 23:01:35 +08:00
return ;
case ZEND_FETCH_DIM_RW :
last_op - > opcode = op ;
last_op - > extended_value = ZEND_ASSIGN_DIM ;
zend_do_op_data ( opline , op2 TSRMLS_CC ) ;
2010-04-20 18:57:45 +08:00
opline - > op2 . var = get_temporary_variable ( CG ( active_op_array ) ) ;
opline - > op2_type = IS_VAR ;
2005-06-08 23:01:35 +08:00
SET_UNUSED ( opline - > result ) ;
2010-04-20 18:57:45 +08:00
GET_NODE ( result , last_op - > result ) ;
2005-06-08 23:01:35 +08:00
return ;
default :
break ;
}
2002-03-10 21:42:37 +08:00
}
2005-06-08 23:01:35 +08:00
opline - > opcode = op ;
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op1 , op1 ) ;
SET_NODE ( opline - > op2 , op2 ) ;
opline - > result_type = IS_VAR ;
opline - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
GET_NODE ( result , opline - > result ) ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void fetch_simple_variable_ex ( znode * result , znode * varname , int bp , zend_uchar op TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
1999-09-20 23:44:30 +08:00
zend_op opline ;
zend_op * opline_ptr ;
1999-04-08 02:10:10 +08:00
2008-01-24 01:55:55 +08:00
if ( varname - > op_type = = IS_CONST ) {
if ( Z_TYPE ( varname - > u . constant ) ! = IS_STRING ) {
convert_to_string ( & varname - > u . constant ) ;
}
2013-09-14 00:45:02 +08:00
2014-02-10 14:04:30 +08:00
if ( ! zend_is_auto_global ( Z_STR ( varname - > u . constant ) TSRMLS_CC ) & &
2013-09-13 21:07:47 +08:00
! ( Z_STRLEN ( varname - > u . constant ) = = ( sizeof ( " this " ) - 1 ) & &
2013-12-17 15:09:52 +08:00
! memcmp ( Z_STRVAL ( varname - > u . constant ) , " this " , sizeof ( " this " ) - 1 ) ) & &
2008-01-24 01:55:55 +08:00
( CG ( active_op_array ) - > last = = 0 | |
CG ( active_op_array ) - > opcodes [ CG ( active_op_array ) - > last - 1 ] . opcode ! = ZEND_BEGIN_SILENCE ) ) {
result - > op_type = IS_CV ;
2014-02-10 14:04:30 +08:00
result - > u . op . var = lookup_cv ( CG ( active_op_array ) , Z_STR ( varname - > u . constant ) TSRMLS_CC ) ;
2014-03-27 20:00:25 +08:00
Z_STR ( varname - > u . constant ) = CG ( active_op_array ) - > vars [ EX_VAR_TO_NUM ( result - > u . op . var ) ] ;
2010-04-20 18:57:45 +08:00
result - > EA = 0 ;
2008-01-24 01:55:55 +08:00
return ;
}
2004-10-05 03:54:35 +08:00
}
1999-09-20 23:44:30 +08:00
if ( bp ) {
opline_ptr = & opline ;
2001-07-28 18:51:54 +08:00
init_op ( opline_ptr TSRMLS_CC ) ;
1999-09-20 23:44:30 +08:00
} else {
2001-07-28 18:51:54 +08:00
opline_ptr = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-09-20 23:44:30 +08:00
}
opline_ptr - > opcode = op ;
2010-04-20 18:57:45 +08:00
opline_ptr - > result_type = IS_VAR ;
opline_ptr - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
SET_NODE ( opline_ptr - > op1 , varname ) ;
GET_NODE ( result , opline_ptr - > result ) ;
1999-09-20 23:44:30 +08:00
SET_UNUSED ( opline_ptr - > op2 ) ;
2010-04-20 18:57:45 +08:00
opline_ptr - > extended_value = ZEND_FETCH_LOCAL ;
2001-08-09 01:18:16 +08:00
2010-04-20 18:57:45 +08:00
if ( varname - > op_type = = IS_CONST ) {
2014-02-10 14:04:30 +08:00
if ( zend_is_auto_global ( Z_STR ( varname - > u . constant ) TSRMLS_CC ) ) {
2010-04-20 18:57:45 +08:00
opline_ptr - > extended_value = ZEND_FETCH_GLOBAL ;
2004-02-10 19:44:17 +08:00
}
2001-08-09 01:18:16 +08:00
}
1999-04-08 02:10:10 +08:00
if ( bp ) {
2014-05-01 02:48:02 +08:00
zend_llist * fetch_list_ptr = zend_stack_top ( & CG ( bp_stack ) ) ;
1999-09-20 23:44:30 +08:00
zend_llist_add_element ( fetch_list_ptr , opline_ptr ) ;
1999-04-08 02:10:10 +08:00
}
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void fetch_simple_variable ( znode * result , znode * varname , int bp TSRMLS_DC ) /* { { { */
1999-09-20 22:45:36 +08:00
{
/* the default mode must be Write, since fetch_simple_variable() is used to define function arguments */
2001-07-28 18:51:54 +08:00
fetch_simple_variable_ex ( result , varname , bp , ZEND_FETCH_W TSRMLS_CC ) ;
1999-09-20 22:45:36 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-09-20 22:45:36 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_fetch_static_member ( znode * result , znode * class_name TSRMLS_DC ) /* { { { */
2001-11-25 16:49:09 +08:00
{
2007-09-29 03:52:53 +08:00
znode class_node ;
2001-11-25 16:49:09 +08:00
zend_llist * fetch_list_ptr ;
zend_llist_element * le ;
zend_op * opline_ptr ;
2004-10-05 03:54:35 +08:00
zend_op opline ;
2001-11-25 16:49:09 +08:00
2010-05-06 18:27:35 +08:00
if ( class_name - > op_type = = IS_CONST & &
ZEND_FETCH_CLASS_DEFAULT = = zend_get_class_fetch_type ( Z_STRVAL ( class_name - > u . constant ) , Z_STRLEN ( class_name - > u . constant ) ) ) {
2013-09-13 18:18:39 +08:00
zend_resolve_class_name ( class_name TSRMLS_CC ) ;
2010-05-06 18:27:35 +08:00
class_node = * class_name ;
} else {
zend_do_fetch_class ( & class_node , class_name TSRMLS_CC ) ;
}
2014-05-01 02:48:02 +08:00
fetch_list_ptr = zend_stack_top ( & CG ( bp_stack ) ) ;
2004-10-05 03:54:35 +08:00
if ( result - > op_type = = IS_CV ) {
init_op ( & opline TSRMLS_CC ) ;
opline . opcode = ZEND_FETCH_W ;
2010-04-20 18:57:45 +08:00
opline . result_type = IS_VAR ;
opline . result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
opline . op1_type = IS_CONST ;
2014-03-27 20:00:25 +08:00
LITERAL_STR ( opline . op1 , STR_COPY ( CG ( active_op_array ) - > vars [ EX_VAR_TO_NUM ( result - > u . op . var ) ] ) ) ;
2010-05-24 22:11:39 +08:00
GET_POLYMORPHIC_CACHE_SLOT ( opline . op1 . constant ) ;
2010-05-06 18:27:35 +08:00
if ( class_node . op_type = = IS_CONST ) {
opline . op2_type = IS_CONST ;
opline . op2 . constant =
zend_add_class_name_literal ( CG ( active_op_array ) , & class_node . u . constant TSRMLS_CC ) ;
} else {
SET_NODE ( opline . op2 , & class_node ) ;
}
2010-04-20 18:57:45 +08:00
GET_NODE ( result , opline . result ) ;
opline . extended_value | = ZEND_FETCH_STATIC_MEMBER ;
opline_ptr = & opline ;
2004-10-05 03:54:35 +08:00
zend_llist_add_element ( fetch_list_ptr , & opline ) ;
} else {
le = fetch_list_ptr - > head ;
2001-11-25 16:49:09 +08:00
2004-10-05 03:54:35 +08:00
opline_ptr = ( zend_op * ) le - > data ;
2010-04-20 18:57:45 +08:00
if ( opline_ptr - > opcode ! = ZEND_FETCH_W & & opline_ptr - > op1_type = = IS_CV ) {
2004-10-05 03:54:35 +08:00
init_op ( & opline TSRMLS_CC ) ;
opline . opcode = ZEND_FETCH_W ;
2010-04-20 18:57:45 +08:00
opline . result_type = IS_VAR ;
opline . result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
opline . op1_type = IS_CONST ;
2014-03-27 20:00:25 +08:00
LITERAL_STR ( opline . op1 , STR_COPY ( CG ( active_op_array ) - > vars [ EX_VAR_TO_NUM ( opline_ptr - > op1 . var ) ] ) ) ;
2010-05-24 22:11:39 +08:00
GET_POLYMORPHIC_CACHE_SLOT ( opline . op1 . constant ) ;
2010-05-06 18:27:35 +08:00
if ( class_node . op_type = = IS_CONST ) {
opline . op2_type = IS_CONST ;
opline . op2 . constant =
zend_add_class_name_literal ( CG ( active_op_array ) , & class_node . u . constant TSRMLS_CC ) ;
} else {
SET_NODE ( opline . op2 , & class_node ) ;
}
2010-04-20 18:57:45 +08:00
opline . extended_value | = ZEND_FETCH_STATIC_MEMBER ;
COPY_NODE ( opline_ptr - > op1 , opline . result ) ;
2004-10-05 03:54:35 +08:00
zend_llist_prepend_element ( fetch_list_ptr , & opline ) ;
} else {
2010-05-24 22:11:39 +08:00
if ( opline_ptr - > op1_type = = IS_CONST ) {
GET_POLYMORPHIC_CACHE_SLOT ( opline_ptr - > op1 . constant ) ;
}
2010-05-06 18:27:35 +08:00
if ( class_node . op_type = = IS_CONST ) {
opline_ptr - > op2_type = IS_CONST ;
opline_ptr - > op2 . constant =
zend_add_class_name_literal ( CG ( active_op_array ) , & class_node . u . constant TSRMLS_CC ) ;
} else {
2010-11-23 18:22:34 +08:00
SET_NODE ( opline_ptr - > op2 , & class_node ) ;
2010-05-06 18:27:35 +08:00
}
2010-04-20 18:57:45 +08:00
opline_ptr - > extended_value | = ZEND_FETCH_STATIC_MEMBER ;
2004-10-05 03:54:35 +08:00
}
}
2001-11-25 16:49:09 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void fetch_array_begin ( znode * result , znode * varname , znode * first_dim TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2001-07-28 18:51:54 +08:00
fetch_simple_variable ( result , varname , 1 TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
2001-07-28 18:51:54 +08:00
fetch_array_dim ( result , result , first_dim TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-04-22 22:52:59 +08:00
void fetch_array_dim ( znode * result , znode * parent , znode * dim TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
1999-09-20 23:44:30 +08:00
zend_op opline ;
2014-05-01 02:48:02 +08:00
zend_llist * fetch_list_ptr = zend_stack_top ( & CG ( bp_stack ) ) ;
2010-08-25 17:14:36 +08:00
if ( zend_is_function_or_method_call ( parent ) ) {
init_op ( & opline TSRMLS_CC ) ;
opline . opcode = ZEND_SEPARATE ;
SET_NODE ( opline . op1 , parent ) ;
SET_UNUSED ( opline . op2 ) ;
opline . result_type = IS_VAR ;
opline . result . var = opline . op1 . var ;
zend_llist_add_element ( fetch_list_ptr , & opline ) ;
}
2013-01-28 10:02:51 +08:00
2001-07-28 18:51:54 +08:00
init_op ( & opline TSRMLS_CC ) ;
1999-09-20 23:44:30 +08:00
opline . opcode = ZEND_FETCH_DIM_W ; /* the backpatching routine assumes W */
2010-04-20 18:57:45 +08:00
opline . result_type = IS_VAR ;
opline . result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
SET_NODE ( opline . op1 , parent ) ;
SET_NODE ( opline . op2 , dim ) ;
if ( opline . op2_type = = IS_CONST & & Z_TYPE ( CONSTANT ( opline . op2 . constant ) ) = = IS_STRING ) {
2010-10-05 19:28:56 +08:00
ulong index ;
2010-04-20 18:57:45 +08:00
2014-06-03 17:10:42 +08:00
if ( ZEND_HANDLE_NUMERIC ( Z_STR ( CONSTANT ( opline . op2 . constant ) ) , index ) ) {
2010-04-20 18:57:45 +08:00
zval_dtor ( & CONSTANT ( opline . op2 . constant ) ) ;
2013-01-28 10:02:51 +08:00
ZVAL_LONG ( & CONSTANT ( opline . op2 . constant ) , index ) ;
2010-04-20 18:57:45 +08:00
}
}
2013-01-28 10:02:51 +08:00
2010-04-20 18:57:45 +08:00
GET_NODE ( result , opline . result ) ;
1999-04-08 02:10:10 +08:00
1999-09-20 23:44:30 +08:00
zend_llist_add_element ( fetch_list_ptr , & opline ) ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-04-22 22:52:59 +08:00
void fetch_string_offset ( znode * result , znode * parent , znode * offset TSRMLS_DC ) /* { { { */
2000-01-29 18:16:04 +08:00
{
2001-07-28 18:51:54 +08:00
fetch_array_dim ( result , parent , offset TSRMLS_CC ) ;
2000-01-29 18:16:04 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2000-01-29 18:16:04 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_print ( znode * result , znode * arg TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2001-07-28 18:51:54 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
2010-04-20 18:57:45 +08:00
opline - > result_type = IS_TMP_VAR ;
opline - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
1999-04-24 08:12:55 +08:00
opline - > opcode = ZEND_PRINT ;
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op1 , arg ) ;
1999-04-08 02:10:10 +08:00
SET_UNUSED ( opline - > op2 ) ;
2010-04-20 18:57:45 +08:00
GET_NODE ( result , opline - > result ) ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_echo ( znode * arg TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2001-07-28 18:51:54 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
1999-04-24 08:12:55 +08:00
opline - > opcode = ZEND_ECHO ;
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op1 , arg ) ;
1999-04-08 02:10:10 +08:00
SET_UNUSED ( opline - > op2 ) ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_abstract_method ( const znode * function_name , znode * modifiers , const znode * body TSRMLS_DC ) /* { { { */
2002-11-21 02:00:23 +08:00
{
2003-03-05 19:14:44 +08:00
char * method_type ;
if ( CG ( active_class_entry ) - > ce_flags & ZEND_ACC_INTERFACE ) {
2006-05-12 05:07:39 +08:00
Z_LVAL ( modifiers - > u . constant ) | = ZEND_ACC_ABSTRACT ;
2003-03-05 19:14:44 +08:00
method_type = " Interface " ;
} else {
method_type = " Abstract " ;
}
2013-09-13 21:07:47 +08:00
if ( Z_LVAL ( modifiers - > u . constant ) & ZEND_ACC_ABSTRACT ) {
if ( Z_LVAL ( modifiers - > u . constant ) & ZEND_ACC_PRIVATE ) {
2014-02-19 16:03:01 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " %s function %s::%s() cannot be declared private " , method_type , CG ( active_class_entry ) - > name - > val , Z_STRVAL ( function_name - > u . constant ) ) ;
2005-06-10 01:12:54 +08:00
}
2006-05-12 05:07:39 +08:00
if ( Z_LVAL ( body - > u . constant ) = = ZEND_ACC_ABSTRACT ) {
2003-02-11 17:48:37 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
2002-11-21 02:00:23 +08:00
2003-02-11 17:48:37 +08:00
opline - > opcode = ZEND_RAISE_ABSTRACT_ERROR ;
SET_UNUSED ( opline - > op1 ) ;
SET_UNUSED ( opline - > op2 ) ;
} else {
/* we had code in the function body */
2014-02-19 16:03:01 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " %s function %s::%s() cannot contain body " , method_type , CG ( active_class_entry ) - > name - > val , Z_STRVAL ( function_name - > u . constant ) ) ;
2003-02-11 17:48:37 +08:00
}
} else {
2013-09-13 21:07:47 +08:00
if ( Z_LVAL ( body - > u . constant ) = = ZEND_ACC_ABSTRACT ) {
2014-02-19 16:03:01 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Non-abstract method %s::%s() must contain body " , CG ( active_class_entry ) - > name - > val , Z_STRVAL ( function_name - > u . constant ) ) ;
2003-02-11 17:48:37 +08:00
}
}
2002-11-21 02:00:23 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2002-11-21 02:00:23 +08:00
2009-07-27 22:11:53 +08:00
static zend_bool opline_is_fetch_this ( const zend_op * opline TSRMLS_DC ) /* { { { */
2004-02-04 22:25:25 +08:00
{
2010-04-20 18:57:45 +08:00
if ( ( opline - > opcode = = ZEND_FETCH_W ) & & ( opline - > op1_type = = IS_CONST )
& & ( Z_TYPE ( CONSTANT ( opline - > op1 . constant ) ) = = IS_STRING )
2013-10-16 22:04:23 +08:00
& & ( ( opline - > extended_value & ZEND_FETCH_STATIC_MEMBER ) ! = ZEND_FETCH_STATIC_MEMBER )
2014-02-10 14:04:30 +08:00
& & ( Z_STRHASH ( CONSTANT ( opline - > op1 . constant ) ) = = THIS_HASHVAL )
2010-04-20 18:57:45 +08:00
& & ( Z_STRLEN ( CONSTANT ( opline - > op1 . constant ) ) = = ( sizeof ( " this " ) - 1 ) )
2013-12-17 15:09:52 +08:00
& & ! memcmp ( Z_STRVAL ( CONSTANT ( opline - > op1 . constant ) ) , " this " , sizeof ( " this " ) - 1 ) ) {
2004-02-04 22:25:25 +08:00
return 1 ;
} else {
return 0 ;
}
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2010-04-20 18:57:45 +08:00
void zend_do_assign ( znode * result , znode * variable , znode * value TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2007-12-28 21:22:00 +08:00
int last_op_number ;
zend_op * opline ;
if ( value - > op_type = = IS_CV ) {
2014-05-01 02:48:02 +08:00
zend_llist * fetch_list_ptr = zend_stack_top ( & CG ( bp_stack ) ) ;
2007-12-28 21:22:00 +08:00
if ( fetch_list_ptr & & fetch_list_ptr - > head ) {
opline = ( zend_op * ) fetch_list_ptr - > head - > data ;
if ( opline - > opcode = = ZEND_FETCH_DIM_W & &
2010-04-20 18:57:45 +08:00
opline - > op1_type = = IS_CV & &
opline - > op1 . var = = value - > u . op . var ) {
2007-12-28 21:22:00 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
opline - > opcode = ZEND_FETCH_R ;
2010-04-20 18:57:45 +08:00
opline - > result_type = IS_VAR ;
opline - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
opline - > op1_type = IS_CONST ;
2014-02-10 14:04:30 +08:00
LITERAL_STR ( opline - > op1 ,
2014-03-27 20:00:25 +08:00
STR_COPY ( CG ( active_op_array ) - > vars [ EX_VAR_TO_NUM ( value - > u . op . var ) ] ) ) ;
2007-12-28 21:22:00 +08:00
SET_UNUSED ( opline - > op2 ) ;
2010-04-20 18:57:45 +08:00
opline - > extended_value = ZEND_FETCH_LOCAL ;
GET_NODE ( value , opline - > result ) ;
2007-12-28 21:22:00 +08:00
}
}
}
2008-05-07 20:04:39 +08:00
zend_do_end_variable_parse ( variable , BP_VAR_W , 0 TSRMLS_CC ) ;
2007-12-28 21:22:00 +08:00
last_op_number = get_next_op_number ( CG ( active_op_array ) ) ;
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
2004-02-04 21:56:41 +08:00
2008-05-07 20:04:39 +08:00
if ( variable - > op_type = = IS_CV ) {
2010-04-20 18:57:45 +08:00
if ( variable - > u . op . var = = CG ( active_op_array ) - > this_var ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot re-assign $this " ) ;
2011-01-20 01:17:52 +08:00
}
2008-05-07 20:04:39 +08:00
} else if ( variable - > op_type = = IS_VAR ) {
2005-10-10 17:50:05 +08:00
int n = 0 ;
while ( last_op_number - n > 0 ) {
zend_op * last_op ;
2006-05-10 07:53:23 +08:00
last_op = & CG ( active_op_array ) - > opcodes [ last_op_number - n - 1 ] ;
2005-10-10 17:50:05 +08:00
2010-04-20 18:57:45 +08:00
if ( last_op - > result_type = = IS_VAR & &
last_op - > result . var = = variable - > u . op . var ) {
2005-10-10 17:50:05 +08:00
if ( last_op - > opcode = = ZEND_FETCH_OBJ_W ) {
if ( n > 0 ) {
2008-11-12 08:44:56 +08:00
int opline_no = ( opline - CG ( active_op_array ) - > opcodes ) / sizeof ( * opline ) ;
2005-10-10 17:50:05 +08:00
* opline = * last_op ;
MAKE_NOP ( last_op ) ;
2008-11-12 08:44:56 +08:00
/* last_op = opline; */
2005-10-10 17:50:05 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
2008-11-12 08:44:56 +08:00
/* get_next_op can realloc, we need to move last_op */
last_op = & CG ( active_op_array ) - > opcodes [ opline_no ] ;
2005-10-10 17:50:05 +08:00
}
last_op - > opcode = ZEND_ASSIGN_OBJ ;
zend_do_op_data ( opline , value TSRMLS_CC ) ;
SET_UNUSED ( opline - > result ) ;
2010-04-20 18:57:45 +08:00
GET_NODE ( result , last_op - > result ) ;
2005-10-10 17:50:05 +08:00
return ;
} else if ( last_op - > opcode = = ZEND_FETCH_DIM_W ) {
if ( n > 0 ) {
2008-11-12 08:44:56 +08:00
int opline_no = ( opline - CG ( active_op_array ) - > opcodes ) / sizeof ( * opline ) ;
2005-10-10 17:50:05 +08:00
* opline = * last_op ;
MAKE_NOP ( last_op ) ;
2008-11-12 08:44:56 +08:00
/* last_op = opline; */
/* TBFixed: this can realloc opcodes, leaving last_op pointing wrong */
2005-10-10 17:50:05 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
2008-11-12 08:44:56 +08:00
/* get_next_op can realloc, we need to move last_op */
last_op = & CG ( active_op_array ) - > opcodes [ opline_no ] ;
2005-10-10 17:50:05 +08:00
}
last_op - > opcode = ZEND_ASSIGN_DIM ;
zend_do_op_data ( opline , value TSRMLS_CC ) ;
2010-04-20 18:57:45 +08:00
opline - > op2 . var = get_temporary_variable ( CG ( active_op_array ) ) ;
opline - > op2_type = IS_VAR ;
2005-10-10 17:50:05 +08:00
SET_UNUSED ( opline - > result ) ;
2010-04-20 18:57:45 +08:00
GET_NODE ( result , last_op - > result ) ;
2005-10-10 17:50:05 +08:00
return ;
} else if ( opline_is_fetch_this ( last_op TSRMLS_CC ) ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot re-assign $this " ) ;
2005-10-10 17:50:05 +08:00
} else {
break ;
}
2005-06-08 23:01:35 +08:00
}
2005-10-10 17:50:05 +08:00
n + + ;
2005-06-08 23:01:35 +08:00
}
2002-03-10 21:42:37 +08:00
}
2005-06-08 23:01:35 +08:00
opline - > opcode = ZEND_ASSIGN ;
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op1 , variable ) ;
SET_NODE ( opline - > op2 , value ) ;
opline - > result_type = IS_VAR ;
opline - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
GET_NODE ( result , opline - > result ) ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_assign_ref ( znode * result , znode * lvar , znode * rvar TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2008-05-07 20:04:39 +08:00
zend_op * opline ;
2005-06-08 23:01:35 +08:00
2008-05-07 20:04:39 +08:00
if ( lvar - > op_type = = IS_CV ) {
2010-04-20 18:57:45 +08:00
if ( lvar - > u . op . var = = CG ( active_op_array ) - > this_var ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot re-assign $this " ) ;
2011-01-20 01:17:52 +08:00
}
2008-05-07 20:04:39 +08:00
} else if ( lvar - > op_type = = IS_VAR ) {
int last_op_number = get_next_op_number ( CG ( active_op_array ) ) ;
if ( last_op_number > 0 ) {
opline = & CG ( active_op_array ) - > opcodes [ last_op_number - 1 ] ;
if ( opline_is_fetch_this ( opline TSRMLS_CC ) ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot re-assign $this " ) ;
2008-05-07 20:04:39 +08:00
}
}
}
2005-06-08 23:01:35 +08:00
2008-05-07 20:04:39 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
2005-06-08 23:01:35 +08:00
opline - > opcode = ZEND_ASSIGN_REF ;
2005-05-06 01:37:25 +08:00
if ( zend_is_function_or_method_call ( rvar ) ) {
2006-05-10 07:53:23 +08:00
opline - > extended_value = ZEND_RETURNS_FUNCTION ;
2010-04-20 18:57:45 +08:00
} else if ( rvar - > EA & ZEND_PARSED_NEW ) {
2008-07-24 19:47:51 +08:00
opline - > extended_value = ZEND_RETURNS_NEW ;
2005-05-06 01:37:25 +08:00
} else {
opline - > extended_value = 0 ;
}
1999-04-08 02:10:10 +08:00
if ( result ) {
2010-04-20 18:57:45 +08:00
opline - > result_type = IS_VAR ;
opline - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
GET_NODE ( result , opline - > result ) ;
1999-04-08 02:10:10 +08:00
} else {
2010-04-20 18:57:45 +08:00
opline - > result_type = IS_UNUSED | EXT_TYPE_UNUSED ;
1999-04-08 02:10:10 +08:00
}
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op1 , lvar ) ;
SET_NODE ( opline - > op2 , rvar ) ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
static inline void do_begin_loop ( TSRMLS_D ) /* { { { */
1999-04-08 02:10:10 +08:00
{
zend_brk_cont_element * brk_cont_element ;
int parent ;
2010-09-15 15:38:52 +08:00
parent = CG ( context ) . current_brk_cont ;
CG ( context ) . current_brk_cont = CG ( active_op_array ) - > last_brk_cont ;
1999-04-08 02:10:10 +08:00
brk_cont_element = get_next_brk_cont_element ( CG ( active_op_array ) ) ;
2006-09-20 05:36:54 +08:00
brk_cont_element - > start = get_next_op_number ( CG ( active_op_array ) ) ;
1999-04-08 02:10:10 +08:00
brk_cont_element - > parent = parent ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
static inline void do_end_loop ( int cont_addr , int has_loop_var TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2008-02-20 20:05:57 +08:00
if ( ! has_loop_var ) {
/* The start fileld is used to free temporary variables in case of exceptions.
* We won ' t try to free something of we don ' t have loop variable .
*/
2010-09-15 15:38:52 +08:00
CG ( active_op_array ) - > brk_cont_array [ CG ( context ) . current_brk_cont ] . start = - 1 ;
2008-02-20 20:05:57 +08:00
}
2010-09-15 15:38:52 +08:00
CG ( active_op_array ) - > brk_cont_array [ CG ( context ) . current_brk_cont ] . cont = cont_addr ;
CG ( active_op_array ) - > brk_cont_array [ CG ( context ) . current_brk_cont ] . brk = get_next_op_number ( CG ( active_op_array ) ) ;
CG ( context ) . current_brk_cont = CG ( active_op_array ) - > brk_cont_array [ CG ( context ) . current_brk_cont ] . parent ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_while_cond ( znode * expr , znode * close_bracket_token TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
int while_cond_op_number = get_next_op_number ( CG ( active_op_array ) ) ;
2001-07-28 18:51:54 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
opline - > opcode = ZEND_JMPZ ;
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op1 , expr ) ;
close_bracket_token - > u . op . opline_num = while_cond_op_number ;
1999-04-08 02:10:10 +08:00
SET_UNUSED ( opline - > op2 ) ;
2001-07-28 18:51:54 +08:00
do_begin_loop ( TSRMLS_C ) ;
1999-04-08 02:10:10 +08:00
INC_BPC ( CG ( active_op_array ) ) ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_while_end ( const znode * while_token , const znode * close_bracket_token TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2001-07-28 18:51:54 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
/* add unconditional jump */
opline - > opcode = ZEND_JMP ;
2010-04-20 18:57:45 +08:00
opline - > op1 . opline_num = while_token - > u . op . opline_num ;
1999-04-08 02:10:10 +08:00
SET_UNUSED ( opline - > op1 ) ;
SET_UNUSED ( opline - > op2 ) ;
2006-05-10 07:53:23 +08:00
1999-04-08 02:10:10 +08:00
/* update while's conditional jmp */
2010-04-20 18:57:45 +08:00
CG ( active_op_array ) - > opcodes [ close_bracket_token - > u . op . opline_num ] . op2 . opline_num = get_next_op_number ( CG ( active_op_array ) ) ;
1999-04-08 02:10:10 +08:00
2010-04-20 18:57:45 +08:00
do_end_loop ( while_token - > u . op . opline_num , 0 TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
DEC_BPC ( CG ( active_op_array ) ) ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_for_cond ( znode * expr , znode * second_semicolon_token TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
int for_cond_op_number = get_next_op_number ( CG ( active_op_array ) ) ;
2001-07-28 18:51:54 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
opline - > opcode = ZEND_JMPZNZ ;
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op1 , expr ) ; /* the conditional expression */
second_semicolon_token - > u . op . opline_num = for_cond_op_number ;
1999-04-08 02:10:10 +08:00
SET_UNUSED ( opline - > op2 ) ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_for_before_statement ( const znode * cond_start , const znode * second_semicolon_token TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2001-07-28 18:51:54 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
opline - > opcode = ZEND_JMP ;
2010-04-20 18:57:45 +08:00
opline - > op1 . opline_num = cond_start - > u . op . opline_num ;
CG ( active_op_array ) - > opcodes [ second_semicolon_token - > u . op . opline_num ] . extended_value = get_next_op_number ( CG ( active_op_array ) ) ;
1999-04-08 02:10:10 +08:00
SET_UNUSED ( opline - > op1 ) ;
SET_UNUSED ( opline - > op2 ) ;
2001-07-28 18:51:54 +08:00
do_begin_loop ( TSRMLS_C ) ;
1999-04-08 02:10:10 +08:00
INC_BPC ( CG ( active_op_array ) ) ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_for_end ( const znode * second_semicolon_token TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2001-07-28 18:51:54 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
opline - > opcode = ZEND_JMP ;
2010-04-20 18:57:45 +08:00
opline - > op1 . opline_num = second_semicolon_token - > u . op . opline_num + 1 ;
CG ( active_op_array ) - > opcodes [ second_semicolon_token - > u . op . opline_num ] . op2 . opline_num = get_next_op_number ( CG ( active_op_array ) ) ;
1999-04-08 02:10:10 +08:00
SET_UNUSED ( opline - > op1 ) ;
SET_UNUSED ( opline - > op2 ) ;
2010-04-20 18:57:45 +08:00
do_end_loop ( second_semicolon_token - > u . op . opline_num + 1 , 0 TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
DEC_BPC ( CG ( active_op_array ) ) ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_pre_incdec ( znode * result , znode * op1 , zend_uchar op TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2005-06-08 23:01:35 +08:00
int last_op_number = get_next_op_number ( CG ( active_op_array ) ) ;
zend_op * opline ;
if ( last_op_number > 0 ) {
zend_op * last_op = & CG ( active_op_array ) - > opcodes [ last_op_number - 1 ] ;
if ( last_op - > opcode = = ZEND_FETCH_OBJ_RW ) {
last_op - > opcode = ( op = = ZEND_PRE_INC ) ? ZEND_PRE_INC_OBJ : ZEND_PRE_DEC_OBJ ;
2010-04-20 18:57:45 +08:00
last_op - > result_type = IS_VAR ;
last_op - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
GET_NODE ( result , last_op - > result ) ;
2005-06-08 23:01:35 +08:00
return ;
}
2002-03-10 21:42:37 +08:00
}
2005-06-08 23:01:35 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
opline - > opcode = op ;
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op1 , op1 ) ;
2005-06-08 23:01:35 +08:00
SET_UNUSED ( opline - > op2 ) ;
2010-04-20 18:57:45 +08:00
opline - > result_type = IS_VAR ;
opline - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
GET_NODE ( result , opline - > result ) ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_post_incdec ( znode * result , znode * op1 , zend_uchar op TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2005-06-08 23:01:35 +08:00
int last_op_number = get_next_op_number ( CG ( active_op_array ) ) ;
zend_op * opline ;
2011-01-20 01:17:52 +08:00
if ( last_op_number > 0 ) {
2005-06-08 23:01:35 +08:00
zend_op * last_op = & CG ( active_op_array ) - > opcodes [ last_op_number - 1 ] ;
if ( last_op - > opcode = = ZEND_FETCH_OBJ_RW ) {
last_op - > opcode = ( op = = ZEND_POST_INC ) ? ZEND_POST_INC_OBJ : ZEND_POST_DEC_OBJ ;
2010-04-20 18:57:45 +08:00
last_op - > result_type = IS_TMP_VAR ;
last_op - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
GET_NODE ( result , last_op - > result ) ;
2005-06-08 23:01:35 +08:00
return ;
}
2002-03-10 21:42:37 +08:00
}
2005-06-08 23:01:35 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
opline - > opcode = op ;
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op1 , op1 ) ;
2005-06-08 23:01:35 +08:00
SET_UNUSED ( opline - > op2 ) ;
2010-04-20 18:57:45 +08:00
opline - > result_type = IS_TMP_VAR ;
opline - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
GET_NODE ( result , opline - > result ) ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_if_cond ( znode * cond , znode * closing_bracket_token TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
int if_cond_op_number = get_next_op_number ( CG ( active_op_array ) ) ;
2001-07-28 18:51:54 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
opline - > opcode = ZEND_JMPZ ;
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op1 , cond ) ;
closing_bracket_token - > u . op . opline_num = if_cond_op_number ;
1999-04-08 02:10:10 +08:00
SET_UNUSED ( opline - > op2 ) ;
INC_BPC ( CG ( active_op_array ) ) ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_if_after_statement ( const znode * closing_bracket_token , unsigned char initialize TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
int if_end_op_number = get_next_op_number ( CG ( active_op_array ) ) ;
2001-07-28 18:51:54 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
zend_llist * jmp_list_ptr ;
opline - > opcode = ZEND_JMP ;
/* save for backpatching */
if ( initialize ) {
zend_llist jmp_list ;
zend_llist_init ( & jmp_list , sizeof ( int ) , NULL , 0 ) ;
2014-05-01 02:28:02 +08:00
zend_stack_push ( & CG ( bp_stack ) , ( void * ) & jmp_list ) ;
1999-04-08 02:10:10 +08:00
}
2014-05-01 02:48:02 +08:00
jmp_list_ptr = zend_stack_top ( & CG ( bp_stack ) ) ;
1999-04-08 02:10:10 +08:00
zend_llist_add_element ( jmp_list_ptr , & if_end_op_number ) ;
2006-05-10 07:53:23 +08:00
2010-04-20 18:57:45 +08:00
CG ( active_op_array ) - > opcodes [ closing_bracket_token - > u . op . opline_num ] . op2 . opline_num = if_end_op_number + 1 ;
1999-04-08 02:10:10 +08:00
SET_UNUSED ( opline - > op1 ) ;
SET_UNUSED ( opline - > op2 ) ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_if_end ( TSRMLS_D ) /* { { { */
1999-04-08 02:10:10 +08:00
{
int next_op_number = get_next_op_number ( CG ( active_op_array ) ) ;
2014-05-01 02:48:02 +08:00
zend_llist * jmp_list_ptr = zend_stack_top ( & CG ( bp_stack ) ) ;
1999-04-08 02:10:10 +08:00
zend_llist_element * le ;
for ( le = jmp_list_ptr - > head ; le ; le = le - > next ) {
2010-04-20 18:57:45 +08:00
CG ( active_op_array ) - > opcodes [ * ( ( int * ) le - > data ) ] . op1 . opline_num = next_op_number ;
1999-04-08 02:10:10 +08:00
}
zend_llist_destroy ( jmp_list_ptr ) ;
zend_stack_del_top ( & CG ( bp_stack ) ) ;
DEC_BPC ( CG ( active_op_array ) ) ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void zend_check_writable_variable ( const znode * variable ) /* { { { */
2001-12-17 03:45:49 +08:00
{
2010-04-20 18:57:45 +08:00
zend_uint type = variable - > EA ;
2004-07-20 16:58:18 +08:00
2001-12-17 03:45:49 +08:00
if ( type & ZEND_PARSED_METHOD_CALL ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Can't use method return value in write context " ) ;
2001-12-17 03:45:49 +08:00
}
2001-12-26 22:46:18 +08:00
if ( type = = ZEND_PARSED_FUNCTION_CALL ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Can't use function return value in write context " ) ;
2001-12-17 03:45:49 +08:00
}
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_begin_variable_parse ( TSRMLS_D ) /* { { { */
1999-04-08 02:10:10 +08:00
{
zend_llist fetch_list ;
1999-09-20 23:44:30 +08:00
zend_llist_init ( & fetch_list , sizeof ( zend_op ) , NULL , 0 ) ;
2014-05-01 02:28:02 +08:00
zend_stack_push ( & CG ( bp_stack ) , ( void * ) & fetch_list ) ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_end_variable_parse ( znode * variable , int type , int arg_offset TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2014-05-01 02:48:02 +08:00
zend_llist * fetch_list_ptr = zend_stack_top ( & CG ( bp_stack ) ) ;
zend_llist_element * le = fetch_list_ptr - > head ;
2008-05-07 20:04:39 +08:00
zend_op * opline = NULL ;
zend_op * opline_ptr ;
zend_uint this_var = - 1 ;
1999-04-08 02:10:10 +08:00
2004-07-20 16:58:18 +08:00
/* TODO: $foo->x->y->z = 1 should fetch "x" and "y" for R or RW, not just W */
2006-05-10 07:53:23 +08:00
2005-07-19 15:33:00 +08:00
if ( le ) {
1999-09-20 23:44:30 +08:00
opline_ptr = ( zend_op * ) le - > data ;
2005-07-19 15:33:00 +08:00
if ( opline_is_fetch_this ( opline_ptr TSRMLS_CC ) ) {
2008-05-07 20:04:39 +08:00
/* convert to FETCH_?(this) into IS_CV */
if ( CG ( active_op_array ) - > last = = 0 | |
CG ( active_op_array ) - > opcodes [ CG ( active_op_array ) - > last - 1 ] . opcode ! = ZEND_BEGIN_SILENCE ) {
2010-04-20 18:57:45 +08:00
this_var = opline_ptr - > result . var ;
2008-05-07 20:04:39 +08:00
if ( CG ( active_op_array ) - > this_var = = - 1 ) {
2014-02-10 14:04:30 +08:00
CG ( active_op_array ) - > this_var = lookup_cv ( CG ( active_op_array ) , Z_STR ( CONSTANT ( opline_ptr - > op1 . constant ) ) TSRMLS_CC ) ;
ZVAL_UNDEF ( & CONSTANT ( opline_ptr - > op1 . constant ) ) ;
2008-05-07 20:04:39 +08:00
} else {
2010-04-20 18:57:45 +08:00
zend_del_literal ( CG ( active_op_array ) , opline_ptr - > op1 . constant ) ;
2008-05-07 20:04:39 +08:00
}
le = le - > next ;
if ( variable - > op_type = = IS_VAR & &
2010-04-20 18:57:45 +08:00
variable - > u . op . var = = this_var ) {
2008-05-07 20:04:39 +08:00
variable - > op_type = IS_CV ;
2010-04-20 18:57:45 +08:00
variable - > u . op . var = CG ( active_op_array ) - > this_var ;
2008-05-07 20:04:39 +08:00
}
2011-01-20 01:17:52 +08:00
} else if ( CG ( active_op_array ) - > this_var = = - 1 ) {
2014-02-10 14:04:30 +08:00
CG ( active_op_array ) - > this_var = lookup_cv ( CG ( active_op_array ) , STR_INIT ( " this " , sizeof ( " this " ) - 1 , 0 ) TSRMLS_CC ) ;
2008-05-07 20:04:39 +08:00
}
1999-04-08 02:10:10 +08:00
}
2002-03-15 23:09:46 +08:00
2008-05-07 20:04:39 +08:00
while ( le ) {
opline_ptr = ( zend_op * ) le - > data ;
2010-08-25 17:14:36 +08:00
if ( opline_ptr - > opcode = = ZEND_SEPARATE ) {
if ( type ! = BP_VAR_R & & type ! = BP_VAR_IS ) {
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
memcpy ( opline , opline_ptr , sizeof ( zend_op ) ) ;
}
le = le - > next ;
continue ;
}
2005-07-19 15:33:00 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
memcpy ( opline , opline_ptr , sizeof ( zend_op ) ) ;
2010-04-20 18:57:45 +08:00
if ( opline - > op1_type = = IS_VAR & &
opline - > op1 . var = = this_var ) {
opline - > op1_type = IS_CV ;
opline - > op1 . var = CG ( active_op_array ) - > this_var ;
2008-05-07 20:04:39 +08:00
}
2005-07-19 15:33:00 +08:00
switch ( type ) {
case BP_VAR_R :
2010-04-20 18:57:45 +08:00
if ( opline - > opcode = = ZEND_FETCH_DIM_W & & opline - > op2_type = = IS_UNUSED ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use [] for reading " ) ;
2005-07-19 15:33:00 +08:00
}
opline - > opcode - = 3 ;
break ;
case BP_VAR_W :
break ;
case BP_VAR_RW :
opline - > opcode + = 3 ;
break ;
case BP_VAR_IS :
2010-04-20 18:57:45 +08:00
if ( opline - > opcode = = ZEND_FETCH_DIM_W & & opline - > op2_type = = IS_UNUSED ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use [] for reading " ) ;
2005-07-19 15:33:00 +08:00
}
opline - > opcode + = 6 ; /* 3+3 */
break ;
case BP_VAR_FUNC_ARG :
opline - > opcode + = 9 ; /* 3+3+3 */
2010-04-20 18:57:45 +08:00
opline - > extended_value | = arg_offset ;
2005-07-19 15:33:00 +08:00
break ;
case BP_VAR_UNSET :
2010-04-20 18:57:45 +08:00
if ( opline - > opcode = = ZEND_FETCH_DIM_W & & opline - > op2_type = = IS_UNUSED ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use [] for unsetting " ) ;
2005-07-19 15:33:00 +08:00
}
opline - > opcode + = 12 ; /* 3+3+3+3 */
break ;
}
le = le - > next ;
}
2008-05-07 20:04:39 +08:00
if ( opline & & type = = BP_VAR_W & & arg_offset ) {
2010-04-20 18:57:45 +08:00
opline - > extended_value | = ZEND_FETCH_MAKE_REF ;
2007-10-23 17:55:11 +08:00
}
1999-04-08 02:10:10 +08:00
}
zend_llist_destroy ( fetch_list_ptr ) ;
zend_stack_del_top ( & CG ( bp_stack ) ) ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_add_string ( znode * result , znode * op1 , znode * op2 TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2007-05-18 21:12:05 +08:00
zend_op * opline ;
if ( Z_STRLEN ( op2 - > u . constant ) > 1 ) {
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
opline - > opcode = ZEND_ADD_STRING ;
} else if ( Z_STRLEN ( op2 - > u . constant ) = = 1 ) {
int ch = * Z_STRVAL ( op2 - > u . constant ) ;
1999-04-08 02:10:10 +08:00
2007-05-18 21:12:05 +08:00
/* Free memory and use ZEND_ADD_CHAR in case of 1 character strings */
2014-02-17 21:59:18 +08:00
STR_FREE ( Z_STR ( op2 - > u . constant ) ) ;
2007-05-18 21:12:05 +08:00
ZVAL_LONG ( & op2 - > u . constant , ch ) ;
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
opline - > opcode = ZEND_ADD_CHAR ;
} else { /* String can be empty after a variable at the end of a heredoc */
2014-02-17 21:59:18 +08:00
STR_FREE ( Z_STR ( op2 - > u . constant ) ) ;
2007-05-18 21:12:05 +08:00
return ;
}
2008-07-26 23:30:28 +08:00
if ( op1 ) {
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op1 , op1 ) ;
SET_NODE ( opline - > result , op1 ) ;
2008-07-26 23:30:28 +08:00
} else {
SET_UNUSED ( opline - > op1 ) ;
2010-04-20 18:57:45 +08:00
opline - > result_type = IS_TMP_VAR ;
opline - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
2008-07-26 23:30:28 +08:00
}
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op2 , op2 ) ;
GET_NODE ( result , opline - > result ) ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_add_variable ( znode * result , znode * op1 , znode * op2 TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2008-07-26 23:30:28 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
2008-07-26 23:30:28 +08:00
opline - > opcode = ZEND_ADD_VAR ;
1999-04-08 02:10:10 +08:00
2008-07-26 23:30:28 +08:00
if ( op1 ) {
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op1 , op1 ) ;
SET_NODE ( opline - > result , op1 ) ;
1999-04-08 02:10:10 +08:00
} else {
2008-07-26 23:30:28 +08:00
SET_UNUSED ( opline - > op1 ) ;
2010-04-20 18:57:45 +08:00
opline - > result_type = IS_TMP_VAR ;
opline - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
1999-04-08 02:10:10 +08:00
}
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op2 , op2 ) ;
GET_NODE ( result , opline - > result ) ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_free ( znode * op1 TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
if ( op1 - > op_type = = IS_TMP_VAR ) {
2001-07-28 18:51:54 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-11-17 02:46:32 +08:00
1999-12-21 04:01:19 +08:00
opline - > opcode = ZEND_FREE ;
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op1 , op1 ) ;
1999-12-21 04:01:19 +08:00
SET_UNUSED ( opline - > op2 ) ;
1999-07-24 19:24:19 +08:00
} else if ( op1 - > op_type = = IS_VAR ) {
1999-04-08 02:10:10 +08:00
zend_op * opline = & CG ( active_op_array ) - > opcodes [ CG ( active_op_array ) - > last - 1 ] ;
2003-01-27 23:13:01 +08:00
while ( opline - > opcode = = ZEND_END_SILENCE | | opline - > opcode = = ZEND_EXT_FCALL_END | | opline - > opcode = = ZEND_OP_DATA ) {
1999-12-21 04:01:19 +08:00
opline - - ;
}
2010-04-20 18:57:45 +08:00
if ( opline - > result_type = = IS_VAR
& & opline - > result . var = = op1 - > u . op . var ) {
2010-07-16 21:38:09 +08:00
if ( opline - > opcode = = ZEND_FETCH_R | |
opline - > opcode = = ZEND_FETCH_DIM_R | |
2011-10-19 03:42:42 +08:00
opline - > opcode = = ZEND_FETCH_OBJ_R | |
opline - > opcode = = ZEND_QM_ASSIGN_VAR ) {
2010-07-16 21:38:09 +08:00
/* It's very rare and useless case. It's better to use
additional FREE opcode and simplify the FETCH handlers
their selves */
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
opline - > opcode = ZEND_FREE ;
SET_NODE ( opline - > op1 , op1 ) ;
SET_UNUSED ( opline - > op2 ) ;
} else {
opline - > result_type | = EXT_TYPE_UNUSED ;
}
1999-04-08 02:10:10 +08:00
} else {
while ( opline > CG ( active_op_array ) - > opcodes ) {
2005-06-10 15:56:40 +08:00
if ( opline - > opcode = = ZEND_FETCH_DIM_R
2010-04-20 18:57:45 +08:00
& & opline - > op1_type = = IS_VAR
& & opline - > op1 . var = = op1 - > u . op . var ) {
2000-02-03 00:47:43 +08:00
/* This should the end of a list() construct
* Mark its result as unused
*/
opline - > extended_value = ZEND_FETCH_STANDARD ;
break ;
2010-04-20 18:57:45 +08:00
} else if ( opline - > result_type = = IS_VAR
& & opline - > result . var = = op1 - > u . op . var ) {
2005-06-10 15:56:40 +08:00
if ( opline - > opcode = = ZEND_NEW ) {
2010-04-20 18:57:45 +08:00
opline - > result_type | = EXT_TYPE_UNUSED ;
2005-06-10 15:56:40 +08:00
}
2000-02-03 00:47:43 +08:00
break ;
1999-04-08 02:10:10 +08:00
}
opline - - ;
}
}
2000-12-18 21:28:32 +08:00
} else if ( op1 - > op_type = = IS_CONST ) {
zval_dtor ( & op1 - > u . constant ) ;
2006-05-10 07:53:23 +08:00
}
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
int zend_do_verify_access_types ( const znode * current_access_type , const znode * new_modifier ) /* { { { */
2002-12-07 01:09:44 +08:00
{
2006-05-10 07:53:23 +08:00
if ( ( Z_LVAL ( current_access_type - > u . constant ) & ZEND_ACC_PPP_MASK )
2007-11-14 00:52:14 +08:00
& & ( Z_LVAL ( new_modifier - > u . constant ) & ZEND_ACC_PPP_MASK ) ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Multiple access type modifiers are not allowed " ) ;
2002-12-07 01:09:44 +08:00
}
2007-11-14 00:52:14 +08:00
if ( ( Z_LVAL ( current_access_type - > u . constant ) & ZEND_ACC_ABSTRACT )
& & ( Z_LVAL ( new_modifier - > u . constant ) & ZEND_ACC_ABSTRACT ) ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Multiple abstract modifiers are not allowed " ) ;
2007-11-14 00:52:14 +08:00
}
if ( ( Z_LVAL ( current_access_type - > u . constant ) & ZEND_ACC_STATIC )
& & ( Z_LVAL ( new_modifier - > u . constant ) & ZEND_ACC_STATIC ) ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Multiple static modifiers are not allowed " ) ;
2007-11-14 00:52:14 +08:00
}
if ( ( Z_LVAL ( current_access_type - > u . constant ) & ZEND_ACC_FINAL )
& & ( Z_LVAL ( new_modifier - > u . constant ) & ZEND_ACC_FINAL ) ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Multiple final modifiers are not allowed " ) ;
2007-11-14 00:52:14 +08:00
}
2006-05-10 07:53:23 +08:00
if ( ( ( Z_LVAL ( current_access_type - > u . constant ) | Z_LVAL ( new_modifier - > u . constant ) ) & ( ZEND_ACC_ABSTRACT | ZEND_ACC_FINAL ) ) = = ( ZEND_ACC_ABSTRACT | ZEND_ACC_FINAL ) ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use the final modifier on an abstract class member " ) ;
2003-03-01 22:57:49 +08:00
}
2006-05-10 07:53:23 +08:00
return ( Z_LVAL ( current_access_type - > u . constant ) | Z_LVAL ( new_modifier - > u . constant ) ) ;
2002-12-07 01:09:44 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2002-12-07 01:09:44 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_begin_function_declaration ( znode * function_token , znode * function_name , int is_method , int return_reference , znode * fn_flags_znode TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
zend_op_array op_array ;
2014-02-10 14:04:30 +08:00
zend_string * name = Z_STR ( function_name - > u . constant ) ;
2010-04-20 18:57:45 +08:00
int function_begin_line = function_token - > u . op . opline_num ;
2003-03-05 19:14:44 +08:00
zend_uint fn_flags ;
2014-02-10 14:04:30 +08:00
zend_string * lcname ;
2007-02-15 18:38:28 +08:00
zend_bool orig_interactive ;
2007-11-22 21:27:13 +08:00
ALLOCA_FLAG ( use_heap )
2003-03-05 19:14:44 +08:00
if ( is_method ) {
if ( CG ( active_class_entry ) - > ce_flags & ZEND_ACC_INTERFACE ) {
2006-05-10 07:53:23 +08:00
if ( ( Z_LVAL ( fn_flags_znode - > u . constant ) & ~ ( ZEND_ACC_STATIC | ZEND_ACC_PUBLIC ) ) ) {
2014-02-19 16:03:01 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Access type for interface method %s::%s() must be omitted " , CG ( active_class_entry ) - > name - > val , Z_STRVAL ( function_name - > u . constant ) ) ;
2003-03-05 19:14:44 +08:00
}
2006-05-10 07:53:23 +08:00
Z_LVAL ( fn_flags_znode - > u . constant ) | = ZEND_ACC_ABSTRACT ; /* propagates to the rest of the parser */
2003-03-05 19:14:44 +08:00
}
2006-05-10 07:53:23 +08:00
fn_flags = Z_LVAL ( fn_flags_znode - > u . constant ) ; /* must be done *after* the above check */
2003-03-05 19:14:44 +08:00
} else {
fn_flags = 0 ;
}
2006-05-10 07:53:23 +08:00
if ( ( fn_flags & ZEND_ACC_STATIC ) & & ( fn_flags & ZEND_ACC_ABSTRACT ) & & ! ( CG ( active_class_entry ) - > ce_flags & ZEND_ACC_INTERFACE ) ) {
2014-02-10 14:04:30 +08:00
zend_error ( E_STRICT , " Static function %s%s%s() should not be abstract " , is_method ? CG ( active_class_entry ) - > name - > val : " " , is_method ? " :: " : " " , Z_STRVAL ( function_name - > u . constant ) ) ;
2006-05-10 07:53:23 +08:00
}
1999-04-08 02:10:10 +08:00
function_token - > u . op_array = CG ( active_op_array ) ;
2007-02-15 18:38:28 +08:00
orig_interactive = CG ( interactive ) ;
CG ( interactive ) = 0 ;
2001-07-28 18:51:54 +08:00
init_op_array ( & op_array , ZEND_USER_FUNCTION , INITIAL_OP_ARRAY_SIZE TSRMLS_CC ) ;
2007-02-15 18:38:28 +08:00
CG ( interactive ) = orig_interactive ;
1999-12-16 04:15:32 +08:00
1999-04-08 02:10:10 +08:00
op_array . function_name = name ;
2010-09-15 15:38:52 +08:00
if ( return_reference ) {
op_array . fn_flags | = ZEND_ACC_RETURN_REFERENCE ;
}
2007-02-15 18:38:28 +08:00
op_array . fn_flags | = fn_flags ;
1999-04-08 02:10:10 +08:00
2005-04-27 21:30:53 +08:00
op_array . scope = is_method ? CG ( active_class_entry ) : NULL ;
2003-03-30 03:20:35 +08:00
op_array . prototype = NULL ;
2002-03-01 22:04:51 +08:00
2003-04-01 04:42:01 +08:00
op_array . line_start = zend_get_compiled_lineno ( TSRMLS_C ) ;
2003-03-20 05:17:47 +08:00
1999-04-08 02:10:10 +08:00
if ( is_method ) {
2014-02-10 14:04:30 +08:00
lcname = STR_ALLOC ( name - > len , 0 ) ;
zend_str_tolower_copy ( lcname - > val , name - > val , name - > len ) ;
lcname = zend_new_interned_string ( lcname TSRMLS_CC ) ;
2014-02-17 21:59:18 +08:00
CG ( active_op_array ) = emalloc ( sizeof ( zend_op_array ) ) ;
memcpy ( CG ( active_op_array ) , & op_array , sizeof ( zend_op_array ) ) ;
if ( zend_hash_add_ptr ( & CG ( active_class_entry ) - > function_table , lcname , CG ( active_op_array ) ) = = NULL ) {
2014-02-10 14:04:30 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot redeclare %s::%s() " , CG ( active_class_entry ) - > name - > val , name - > val ) ;
2002-11-11 06:02:28 +08:00
}
2003-02-13 00:28:34 +08:00
2014-05-01 02:28:02 +08:00
zend_stack_push ( & CG ( context_stack ) , ( void * ) & CG ( context ) ) ;
2010-09-15 15:38:52 +08:00
zend_init_compiler_context ( TSRMLS_C ) ;
2002-12-07 01:09:44 +08:00
if ( fn_flags & ZEND_ACC_ABSTRACT ) {
2004-03-10 00:38:37 +08:00
CG ( active_class_entry ) - > ce_flags | = ZEND_ACC_IMPLICIT_ABSTRACT_CLASS ;
2002-12-07 01:09:44 +08:00
}
2002-11-11 06:02:28 +08:00
2003-02-13 00:28:34 +08:00
if ( ! ( fn_flags & ZEND_ACC_PPP_MASK ) ) {
fn_flags | = ZEND_ACC_PUBLIC ;
}
2008-06-03 22:07:15 +08:00
if ( CG ( active_class_entry ) - > ce_flags & ZEND_ACC_INTERFACE ) {
2014-02-10 14:04:30 +08:00
if ( ( name - > len = = sizeof ( ZEND_CALL_FUNC_NAME ) - 1 ) & & ( ! memcmp ( lcname - > val , ZEND_CALL_FUNC_NAME , sizeof ( ZEND_CALL_FUNC_NAME ) - 1 ) ) ) {
2008-06-03 22:07:15 +08:00
if ( fn_flags & ( ( ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC ) ^ ZEND_ACC_PUBLIC ) ) {
2009-06-07 23:46:54 +08:00
zend_error ( E_WARNING , " The magic method __call() must have public visibility and cannot be static " ) ;
2008-06-03 22:07:15 +08:00
}
2014-02-10 14:04:30 +08:00
} else if ( ( name - > len = = sizeof ( ZEND_CALLSTATIC_FUNC_NAME ) - 1 ) & & ( ! memcmp ( lcname - > val , ZEND_CALLSTATIC_FUNC_NAME , sizeof ( ZEND_CALLSTATIC_FUNC_NAME ) - 1 ) ) ) {
2008-06-03 22:07:15 +08:00
if ( ( fn_flags & ( ZEND_ACC_PPP_MASK ^ ZEND_ACC_PUBLIC ) ) | | ( fn_flags & ZEND_ACC_STATIC ) = = 0 ) {
2008-06-11 07:09:09 +08:00
zend_error ( E_WARNING , " The magic method __callStatic() must have public visibility and be static " ) ;
2008-06-03 22:07:15 +08:00
}
2014-02-10 14:04:30 +08:00
} else if ( ( name - > len = = sizeof ( ZEND_GET_FUNC_NAME ) - 1 ) & & ( ! memcmp ( lcname - > val , ZEND_GET_FUNC_NAME , sizeof ( ZEND_GET_FUNC_NAME ) - 1 ) ) ) {
2008-06-03 22:07:15 +08:00
if ( fn_flags & ( ( ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC ) ^ ZEND_ACC_PUBLIC ) ) {
2009-06-07 23:46:54 +08:00
zend_error ( E_WARNING , " The magic method __get() must have public visibility and cannot be static " ) ;
2008-06-03 22:07:15 +08:00
}
2014-02-10 14:04:30 +08:00
} else if ( ( name - > len = = sizeof ( ZEND_SET_FUNC_NAME ) - 1 ) & & ( ! memcmp ( lcname - > val , ZEND_SET_FUNC_NAME , sizeof ( ZEND_SET_FUNC_NAME ) - 1 ) ) ) {
2008-06-03 22:07:15 +08:00
if ( fn_flags & ( ( ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC ) ^ ZEND_ACC_PUBLIC ) ) {
2009-06-07 23:46:54 +08:00
zend_error ( E_WARNING , " The magic method __set() must have public visibility and cannot be static " ) ;
2008-06-03 22:07:15 +08:00
}
2014-02-10 14:04:30 +08:00
} else if ( ( name - > len = = sizeof ( ZEND_UNSET_FUNC_NAME ) - 1 ) & & ( ! memcmp ( lcname - > val , ZEND_UNSET_FUNC_NAME , sizeof ( ZEND_UNSET_FUNC_NAME ) - 1 ) ) ) {
2008-06-03 22:07:15 +08:00
if ( fn_flags & ( ( ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC ) ^ ZEND_ACC_PUBLIC ) ) {
2009-06-07 23:46:54 +08:00
zend_error ( E_WARNING , " The magic method __unset() must have public visibility and cannot be static " ) ;
2008-06-03 22:07:15 +08:00
}
2014-02-10 14:04:30 +08:00
} else if ( ( name - > len = = sizeof ( ZEND_ISSET_FUNC_NAME ) - 1 ) & & ( ! memcmp ( lcname - > val , ZEND_ISSET_FUNC_NAME , sizeof ( ZEND_ISSET_FUNC_NAME ) - 1 ) ) ) {
2008-06-03 22:07:15 +08:00
if ( fn_flags & ( ( ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC ) ^ ZEND_ACC_PUBLIC ) ) {
2009-06-07 23:46:54 +08:00
zend_error ( E_WARNING , " The magic method __isset() must have public visibility and cannot be static " ) ;
2008-06-03 22:07:15 +08:00
}
2014-02-10 14:04:30 +08:00
} else if ( ( name - > len = = sizeof ( ZEND_TOSTRING_FUNC_NAME ) - 1 ) & & ( ! memcmp ( lcname - > val , ZEND_TOSTRING_FUNC_NAME , sizeof ( ZEND_TOSTRING_FUNC_NAME ) - 1 ) ) ) {
2008-06-03 22:07:15 +08:00
if ( fn_flags & ( ( ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC ) ^ ZEND_ACC_PUBLIC ) ) {
2009-06-07 23:46:54 +08:00
zend_error ( E_WARNING , " The magic method __toString() must have public visibility and cannot be static " ) ;
2008-06-03 22:07:15 +08:00
}
2014-02-10 14:04:30 +08:00
} else if ( ( name - > len = = sizeof ( ZEND_INVOKE_FUNC_NAME ) - 1 ) & & ( ! memcmp ( lcname - > val , ZEND_INVOKE_FUNC_NAME , sizeof ( ZEND_INVOKE_FUNC_NAME ) - 1 ) ) ) {
2013-03-08 10:34:17 +08:00
if ( fn_flags & ( ( ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC ) ^ ZEND_ACC_PUBLIC ) ) {
zend_error ( E_WARNING , " The magic method __invoke() must have public visibility and cannot be static " ) ;
}
2014-02-18 11:13:00 +08:00
2014-04-26 04:32:51 +08:00
} else if ( ( name - > len = = sizeof ( ZEND_DEBUGINFO_FUNC_NAME ) - 1 ) & & ( ! memcmp ( lcname - > val , ZEND_DEBUGINFO_FUNC_NAME , sizeof ( ZEND_DEBUGINFO_FUNC_NAME ) - 1 ) ) ) {
2014-02-18 11:13:00 +08:00
if ( fn_flags & ( ( ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC ) ^ ZEND_ACC_PUBLIC ) ) {
zend_error ( E_WARNING , " The magic method __debugInfo() must have public visibility and cannot be static " ) ;
}
2008-06-03 22:07:15 +08:00
}
} else {
2010-04-05 07:28:20 +08:00
char * class_lcname ;
2013-01-28 10:02:51 +08:00
2014-02-10 14:04:30 +08:00
class_lcname = do_alloca ( CG ( active_class_entry ) - > name - > len + 1 , use_heap ) ;
zend_str_tolower_copy ( class_lcname , CG ( active_class_entry ) - > name - > val , CG ( active_class_entry ) - > name - > len ) ;
2004-08-27 06:25:55 +08:00
/* Improve after RC: cache the lowercase class name */
2014-02-10 14:04:30 +08:00
if ( ( CG ( active_class_entry ) - > name - > len = = name - > len ) & & ( ( CG ( active_class_entry ) - > ce_flags & ZEND_ACC_TRAIT ) ! = ZEND_ACC_TRAIT ) & & ( ! memcmp ( class_lcname , lcname - > val , name - > len ) ) ) {
2010-06-27 03:19:16 +08:00
if ( ! CG ( active_class_entry ) - > constructor ) {
2004-08-27 06:25:55 +08:00
CG ( active_class_entry ) - > constructor = ( zend_function * ) CG ( active_op_array ) ;
}
2014-02-18 20:27:38 +08:00
} else if ( ( name - > len = = sizeof ( ZEND_CONSTRUCTOR_FUNC_NAME ) - 1 ) & & ( ! memcmp ( lcname - > val , ZEND_CONSTRUCTOR_FUNC_NAME , sizeof ( ZEND_CONSTRUCTOR_FUNC_NAME ) - 1 ) ) ) {
2004-08-27 06:25:55 +08:00
if ( CG ( active_class_entry ) - > constructor ) {
2014-02-10 14:04:30 +08:00
zend_error ( E_STRICT , " Redefining already defined constructor for class %s " , CG ( active_class_entry ) - > name - > val ) ;
2004-08-27 06:25:55 +08:00
}
2004-03-26 02:00:50 +08:00
CG ( active_class_entry ) - > constructor = ( zend_function * ) CG ( active_op_array ) ;
2014-02-10 14:04:30 +08:00
} else if ( ( name - > len = = sizeof ( ZEND_DESTRUCTOR_FUNC_NAME ) - 1 ) & & ( ! memcmp ( lcname - > val , ZEND_DESTRUCTOR_FUNC_NAME , sizeof ( ZEND_DESTRUCTOR_FUNC_NAME ) - 1 ) ) ) {
2004-08-27 06:25:55 +08:00
CG ( active_class_entry ) - > destructor = ( zend_function * ) CG ( active_op_array ) ;
2014-02-10 14:04:30 +08:00
} else if ( ( name - > len = = sizeof ( ZEND_CLONE_FUNC_NAME ) - 1 ) & & ( ! memcmp ( lcname - > val , ZEND_CLONE_FUNC_NAME , sizeof ( ZEND_CLONE_FUNC_NAME ) - 1 ) ) ) {
2004-08-27 06:25:55 +08:00
CG ( active_class_entry ) - > clone = ( zend_function * ) CG ( active_op_array ) ;
2014-02-10 14:04:30 +08:00
} else if ( ( name - > len = = sizeof ( ZEND_CALL_FUNC_NAME ) - 1 ) & & ( ! memcmp ( lcname - > val , ZEND_CALL_FUNC_NAME , sizeof ( ZEND_CALL_FUNC_NAME ) - 1 ) ) ) {
2008-06-03 22:07:15 +08:00
if ( fn_flags & ( ( ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC ) ^ ZEND_ACC_PUBLIC ) ) {
2009-06-07 23:46:54 +08:00
zend_error ( E_WARNING , " The magic method __call() must have public visibility and cannot be static " ) ;
2008-06-03 22:07:15 +08:00
}
2004-08-27 06:25:55 +08:00
CG ( active_class_entry ) - > __call = ( zend_function * ) CG ( active_op_array ) ;
2014-02-10 14:04:30 +08:00
} else if ( ( name - > len = = sizeof ( ZEND_CALLSTATIC_FUNC_NAME ) - 1 ) & & ( ! memcmp ( lcname - > val , ZEND_CALLSTATIC_FUNC_NAME , sizeof ( ZEND_CALLSTATIC_FUNC_NAME ) - 1 ) ) ) {
2008-06-03 22:07:15 +08:00
if ( ( fn_flags & ( ZEND_ACC_PPP_MASK ^ ZEND_ACC_PUBLIC ) ) | | ( fn_flags & ZEND_ACC_STATIC ) = = 0 ) {
2008-06-11 07:09:09 +08:00
zend_error ( E_WARNING , " The magic method __callStatic() must have public visibility and be static " ) ;
2008-06-03 22:07:15 +08:00
}
2007-09-29 16:52:40 +08:00
CG ( active_class_entry ) - > __callstatic = ( zend_function * ) CG ( active_op_array ) ;
2014-02-10 14:04:30 +08:00
} else if ( ( name - > len = = sizeof ( ZEND_GET_FUNC_NAME ) - 1 ) & & ( ! memcmp ( lcname - > val , ZEND_GET_FUNC_NAME , sizeof ( ZEND_GET_FUNC_NAME ) - 1 ) ) ) {
2008-06-03 22:07:15 +08:00
if ( fn_flags & ( ( ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC ) ^ ZEND_ACC_PUBLIC ) ) {
2009-06-07 23:46:54 +08:00
zend_error ( E_WARNING , " The magic method __get() must have public visibility and cannot be static " ) ;
2008-06-03 22:07:15 +08:00
}
2004-08-27 06:25:55 +08:00
CG ( active_class_entry ) - > __get = ( zend_function * ) CG ( active_op_array ) ;
2014-02-10 14:04:30 +08:00
} else if ( ( name - > len = = sizeof ( ZEND_SET_FUNC_NAME ) - 1 ) & & ( ! memcmp ( lcname - > val , ZEND_SET_FUNC_NAME , sizeof ( ZEND_SET_FUNC_NAME ) - 1 ) ) ) {
2008-06-03 22:07:15 +08:00
if ( fn_flags & ( ( ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC ) ^ ZEND_ACC_PUBLIC ) ) {
2009-06-07 23:46:54 +08:00
zend_error ( E_WARNING , " The magic method __set() must have public visibility and cannot be static " ) ;
2008-06-03 22:07:15 +08:00
}
2004-08-27 06:25:55 +08:00
CG ( active_class_entry ) - > __set = ( zend_function * ) CG ( active_op_array ) ;
2014-02-10 14:04:30 +08:00
} else if ( ( name - > len = = sizeof ( ZEND_UNSET_FUNC_NAME ) - 1 ) & & ( ! memcmp ( lcname - > val , ZEND_UNSET_FUNC_NAME , sizeof ( ZEND_UNSET_FUNC_NAME ) - 1 ) ) ) {
2008-06-03 22:07:15 +08:00
if ( fn_flags & ( ( ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC ) ^ ZEND_ACC_PUBLIC ) ) {
2009-06-07 23:46:54 +08:00
zend_error ( E_WARNING , " The magic method __unset() must have public visibility and cannot be static " ) ;
2008-06-03 22:07:15 +08:00
}
2005-07-08 00:07:09 +08:00
CG ( active_class_entry ) - > __unset = ( zend_function * ) CG ( active_op_array ) ;
2014-02-10 14:04:30 +08:00
} else if ( ( name - > len = = sizeof ( ZEND_ISSET_FUNC_NAME ) - 1 ) & & ( ! memcmp ( lcname - > val , ZEND_ISSET_FUNC_NAME , sizeof ( ZEND_ISSET_FUNC_NAME ) - 1 ) ) ) {
2008-06-03 22:07:15 +08:00
if ( fn_flags & ( ( ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC ) ^ ZEND_ACC_PUBLIC ) ) {
2009-06-07 23:46:54 +08:00
zend_error ( E_WARNING , " The magic method __isset() must have public visibility and cannot be static " ) ;
2008-06-03 22:07:15 +08:00
}
2005-07-08 00:07:09 +08:00
CG ( active_class_entry ) - > __isset = ( zend_function * ) CG ( active_op_array ) ;
2014-02-10 14:04:30 +08:00
} else if ( ( name - > len = = sizeof ( ZEND_TOSTRING_FUNC_NAME ) - 1 ) & & ( ! memcmp ( lcname - > val , ZEND_TOSTRING_FUNC_NAME , sizeof ( ZEND_TOSTRING_FUNC_NAME ) - 1 ) ) ) {
2008-06-03 22:07:15 +08:00
if ( fn_flags & ( ( ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC ) ^ ZEND_ACC_PUBLIC ) ) {
2009-06-07 23:46:54 +08:00
zend_error ( E_WARNING , " The magic method __toString() must have public visibility and cannot be static " ) ;
2013-01-28 10:02:51 +08:00
}
2006-05-10 07:53:23 +08:00
CG ( active_class_entry ) - > __tostring = ( zend_function * ) CG ( active_op_array ) ;
2014-02-10 14:04:30 +08:00
} else if ( ( name - > len = = sizeof ( ZEND_INVOKE_FUNC_NAME ) - 1 ) & & ( ! memcmp ( lcname - > val , ZEND_INVOKE_FUNC_NAME , sizeof ( ZEND_INVOKE_FUNC_NAME ) - 1 ) ) ) {
2013-03-08 10:34:17 +08:00
if ( fn_flags & ( ( ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC ) ^ ZEND_ACC_PUBLIC ) ) {
zend_error ( E_WARNING , " The magic method __invoke() must have public visibility and cannot be static " ) ;
}
2014-04-26 04:32:51 +08:00
} else if ( ( name - > len = = sizeof ( ZEND_DEBUGINFO_FUNC_NAME ) - 1 ) & & ( ! memcmp ( lcname - > val , ZEND_DEBUGINFO_FUNC_NAME , sizeof ( ZEND_DEBUGINFO_FUNC_NAME ) - 1 ) ) ) {
2014-02-18 11:13:00 +08:00
if ( fn_flags & ( ( ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC ) ^ ZEND_ACC_PUBLIC ) ) {
zend_error ( E_WARNING , " The magic method __debugInfo() must have public visibility and cannot be static " ) ;
}
CG ( active_class_entry ) - > __debugInfo = ( zend_function * ) CG ( active_op_array ) ;
2004-08-27 06:25:55 +08:00
} else if ( ! ( fn_flags & ZEND_ACC_STATIC ) ) {
CG ( active_op_array ) - > fn_flags | = ZEND_ACC_ALLOW_STATIC ;
2004-03-04 18:02:59 +08:00
}
2010-04-05 07:28:20 +08:00
free_alloca ( class_lcname , use_heap ) ;
2001-11-03 19:59:14 +08:00
}
2003-09-17 18:14:12 +08:00
2014-02-10 14:04:30 +08:00
STR_RELEASE ( lcname ) ;
1999-04-08 02:10:10 +08:00
} else {
2001-07-28 18:51:54 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
2010-04-20 18:57:45 +08:00
zval key ;
2014-02-10 14:04:30 +08:00
zval * ns_name ;
1999-05-15 23:47:24 +08:00
2014-02-10 14:04:30 +08:00
if ( Z_TYPE ( CG ( current_namespace ) ) ! = IS_UNDEF ) {
2012-06-08 16:24:49 +08:00
/* Prefix function name with current namespace name */
2007-09-29 03:52:53 +08:00
znode tmp ;
2014-02-10 14:04:30 +08:00
ZVAL_DUP ( & tmp . u . constant , & CG ( current_namespace ) ) ;
2007-09-29 03:52:53 +08:00
zend_do_build_namespace_name ( & tmp , & tmp , function_name TSRMLS_CC ) ;
2014-02-10 14:04:30 +08:00
op_array . function_name = Z_STR ( tmp . u . constant ) ;
lcname = STR_ALLOC ( Z_STRLEN ( tmp . u . constant ) , 0 ) ;
zend_str_tolower_copy ( lcname - > val , Z_STRVAL ( tmp . u . constant ) , Z_STRLEN ( tmp . u . constant ) ) ;
2010-04-20 19:05:54 +08:00
} else {
2014-02-10 14:04:30 +08:00
lcname = STR_ALLOC ( name - > len , 0 ) ;
zend_str_tolower_copy ( lcname - > val , name - > val , name - > len ) ;
2007-09-29 03:52:53 +08:00
}
2013-08-24 05:39:42 +08:00
/* Function name must not conflict with import names */
if ( CG ( current_import_function ) & &
2014-02-10 14:04:30 +08:00
( ns_name = zend_hash_find ( CG ( current_import_function ) , lcname ) ) ! = NULL ) {
2013-08-24 05:39:42 +08:00
2014-02-10 14:04:30 +08:00
char * tmp = zend_str_tolower_dup ( Z_STRVAL_P ( ns_name ) , Z_STRLEN_P ( ns_name ) ) ;
2013-08-24 05:39:42 +08:00
2014-02-10 14:04:30 +08:00
if ( Z_STRLEN_P ( ns_name ) ! = Z_STRLEN ( function_name - > u . constant ) | |
2014-02-18 05:41:23 +08:00
memcmp ( tmp , lcname - > val , Z_STRLEN ( function_name - > u . constant ) ) ) {
2013-08-24 05:39:42 +08:00
zend_error ( E_COMPILE_ERROR , " Cannot declare function %s because the name is already in use " , Z_STRVAL ( function_name - > u . constant ) ) ;
}
efree ( tmp ) ;
}
2002-09-25 03:05:53 +08:00
opline - > opcode = ZEND_DECLARE_FUNCTION ;
2010-04-20 18:57:45 +08:00
opline - > op1_type = IS_CONST ;
2014-02-10 14:04:30 +08:00
build_runtime_defined_function_key ( & key , lcname - > val , lcname - > len TSRMLS_CC ) ;
2010-09-15 15:38:52 +08:00
opline - > op1 . constant = zend_add_literal ( CG ( active_op_array ) , & key TSRMLS_CC ) ;
2010-04-20 18:57:45 +08:00
opline - > op2_type = IS_CONST ;
2014-02-10 14:04:30 +08:00
LITERAL_STR ( opline - > op2 , STR_COPY ( lcname ) ) ;
1999-05-15 23:47:24 +08:00
opline - > extended_value = ZEND_DECLARE_FUNCTION ;
2014-02-17 21:59:18 +08:00
CG ( active_op_array ) = emalloc ( sizeof ( zend_op_array ) ) ;
memcpy ( CG ( active_op_array ) , & op_array , sizeof ( zend_op_array ) ) ;
zend_hash_update_ptr ( CG ( function_table ) , Z_STR ( key ) , CG ( active_op_array ) ) ;
2014-05-01 02:28:02 +08:00
zend_stack_push ( & CG ( context_stack ) , ( void * ) & CG ( context ) ) ;
2010-09-15 15:38:52 +08:00
zend_init_compiler_context ( TSRMLS_C ) ;
2014-02-10 14:04:30 +08:00
STR_RELEASE ( lcname ) ;
1999-04-08 02:10:10 +08:00
}
2008-03-18 16:36:30 +08:00
if ( CG ( compiler_options ) & ZEND_COMPILE_EXTENDED_INFO ) {
2001-07-28 18:51:54 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
opline - > opcode = ZEND_EXT_NOP ;
opline - > lineno = function_begin_line ;
SET_UNUSED ( opline - > op1 ) ;
SET_UNUSED ( opline - > op2 ) ;
}
2006-05-10 07:53:23 +08:00
1999-09-09 22:15:17 +08:00
{
2013-08-05 07:06:24 +08:00
/* Push a separator to the switch stack */
1999-09-09 22:15:17 +08:00
zend_switch_entry switch_entry ;
2006-05-10 07:53:23 +08:00
2004-03-06 01:18:34 +08:00
switch_entry . cond . op_type = IS_UNUSED ;
1999-09-09 22:15:17 +08:00
switch_entry . default_case = 0 ;
switch_entry . control_var = 0 ;
2014-05-01 02:28:02 +08:00
zend_stack_push ( & CG ( switch_cond_stack ) , ( void * ) & switch_entry ) ;
2012-05-19 20:21:49 +08:00
}
1999-09-09 22:15:17 +08:00
2012-05-19 20:21:49 +08:00
{
/* Push a separator to the foreach stack */
zend_op dummy_opline ;
2004-03-05 21:04:21 +08:00
2012-05-19 20:21:49 +08:00
dummy_opline . result_type = IS_UNUSED ;
2004-03-05 21:04:21 +08:00
2014-05-01 02:28:02 +08:00
zend_stack_push ( & CG ( foreach_copy_stack ) , ( void * ) & dummy_opline ) ;
1999-09-09 22:15:17 +08:00
}
2003-04-03 00:51:49 +08:00
if ( CG ( doc_comment ) ) {
2005-06-08 02:11:56 +08:00
CG ( active_op_array ) - > doc_comment = CG ( doc_comment ) ;
CG ( doc_comment ) = NULL ;
2003-04-03 00:51:49 +08:00
}
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2010-04-20 03:45:03 +08:00
void zend_do_begin_lambda_function_declaration ( znode * result , znode * function_token , int return_reference , int is_static TSRMLS_DC ) /* { { { */
2008-07-14 17:49:03 +08:00
{
znode function_name ;
zend_op_array * current_op_array = CG ( active_op_array ) ;
int current_op_number = get_next_op_number ( CG ( active_op_array ) ) ;
zend_op * current_op ;
function_name . op_type = IS_CONST ;
2014-02-10 14:04:30 +08:00
ZVAL_STRINGL ( & function_name . u . constant , " {closure} " , sizeof ( " {closure} " ) - 1 ) ;
2008-07-14 17:49:03 +08:00
zend_do_begin_function_declaration ( function_token , & function_name , 0 , return_reference , NULL TSRMLS_CC ) ;
result - > op_type = IS_TMP_VAR ;
2010-04-20 18:57:45 +08:00
result - > u . op . var = get_temporary_variable ( current_op_array ) ;
2008-07-14 17:49:03 +08:00
current_op = & current_op_array - > opcodes [ current_op_number ] ;
current_op - > opcode = ZEND_DECLARE_LAMBDA_FUNCTION ;
2010-04-20 18:57:45 +08:00
zend_del_literal ( current_op_array , current_op - > op2 . constant ) ;
SET_UNUSED ( current_op - > op2 ) ;
SET_NODE ( current_op - > result , result ) ;
2010-04-20 03:45:03 +08:00
if ( is_static ) {
2011-01-20 01:17:52 +08:00
CG ( active_op_array ) - > fn_flags | = ZEND_ACC_STATIC ;
2010-04-20 03:45:03 +08:00
}
2008-11-04 03:28:32 +08:00
CG ( active_op_array ) - > fn_flags | = ZEND_ACC_CLOSURE ;
2008-07-14 17:49:03 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2008-07-14 17:49:03 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_handle_exception ( TSRMLS_D ) /* { { { */
2004-02-03 20:17:09 +08:00
{
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
opline - > opcode = ZEND_HANDLE_EXCEPTION ;
SET_UNUSED ( opline - > op1 ) ;
SET_UNUSED ( opline - > op2 ) ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
2004-02-03 20:17:09 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_end_function_declaration ( const znode * function_token TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2004-08-02 16:27:57 +08:00
char lcname [ 16 ] ;
int name_len ;
2001-07-28 18:51:54 +08:00
zend_do_extended_info ( TSRMLS_C ) ;
zend_do_return ( NULL , 0 TSRMLS_CC ) ;
2004-02-03 20:17:09 +08:00
2001-07-31 12:53:54 +08:00
pass_two ( CG ( active_op_array ) TSRMLS_CC ) ;
2013-03-28 04:03:40 +08:00
zend_release_labels ( 0 TSRMLS_CC ) ;
2004-02-02 20:28:19 +08:00
2004-08-02 16:27:57 +08:00
if ( CG ( active_class_entry ) ) {
2004-09-10 00:51:45 +08:00
zend_check_magic_method_implementation ( CG ( active_class_entry ) , ( zend_function * ) CG ( active_op_array ) , E_COMPILE_ERROR TSRMLS_CC ) ;
2004-08-02 16:27:57 +08:00
} else {
2013-01-28 10:02:51 +08:00
/* we don't care if the function name is longer, in fact lowercasing only
2004-09-10 00:51:45 +08:00
* the beginning of the name speeds up the check process */
2014-02-10 14:04:30 +08:00
name_len = CG ( active_op_array ) - > function_name - > len ;
zend_str_tolower_copy ( lcname , CG ( active_op_array ) - > function_name - > val , MIN ( name_len , sizeof ( lcname ) - 1 ) ) ;
2004-09-10 00:51:45 +08:00
lcname [ sizeof ( lcname ) - 1 ] = ' \0 ' ; /* zend_str_tolower_copy won't necessarily set the zero byte */
2004-08-03 06:41:34 +08:00
if ( name_len = = sizeof ( ZEND_AUTOLOAD_FUNC_NAME ) - 1 & & ! memcmp ( lcname , ZEND_AUTOLOAD_FUNC_NAME , sizeof ( ZEND_AUTOLOAD_FUNC_NAME ) ) & & CG ( active_op_array ) - > num_args ! = 1 ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " %s() must take exactly 1 argument " , ZEND_AUTOLOAD_FUNC_NAME ) ;
2013-01-28 10:02:51 +08:00
}
2004-02-02 20:28:19 +08:00
}
2003-04-01 04:42:01 +08:00
CG ( active_op_array ) - > line_end = zend_get_compiled_lineno ( TSRMLS_C ) ;
1999-04-08 02:10:10 +08:00
CG ( active_op_array ) = function_token - > u . op_array ;
1999-09-09 22:15:17 +08:00
2004-02-02 20:28:19 +08:00
2013-07-24 07:55:43 +08:00
/* Pop the switch and foreach separators */
1999-09-09 22:15:17 +08:00
zend_stack_del_top ( & CG ( switch_cond_stack ) ) ;
zend_stack_del_top ( & CG ( foreach_copy_stack ) ) ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_receive_param ( zend_uchar op , znode * varname , znode * initialization , znode * class_type , zend_uchar pass_by_reference , zend_bool is_variadic TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2007-05-04 14:18:53 +08:00
zend_op * opline ;
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_arg_info * cur_arg_info ;
2010-04-20 19:16:39 +08:00
znode var ;
1999-04-08 02:10:10 +08:00
2014-02-10 14:04:30 +08:00
if ( zend_is_auto_global ( Z_STR ( varname - > u . constant ) TSRMLS_CC ) ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot re-assign auto-global variable %s " , Z_STRVAL ( varname - > u . constant ) ) ;
2010-04-20 19:16:39 +08:00
} else {
var . op_type = IS_CV ;
2014-02-10 14:04:30 +08:00
var . u . op . var = lookup_cv ( CG ( active_op_array ) , Z_STR ( varname - > u . constant ) TSRMLS_CC ) ;
2014-03-27 20:00:25 +08:00
Z_STR ( varname - > u . constant ) = CG ( active_op_array ) - > vars [ EX_VAR_TO_NUM ( var . u . op . var ) ] ;
2010-04-20 19:16:39 +08:00
var . EA = 0 ;
2014-02-10 14:04:30 +08:00
if ( Z_STRHASH ( varname - > u . constant ) = = THIS_HASHVAL & &
2011-06-20 05:56:09 +08:00
Z_STRLEN ( varname - > u . constant ) = = sizeof ( " this " ) - 1 & &
2010-04-20 19:16:39 +08:00
! memcmp ( Z_STRVAL ( varname - > u . constant ) , " this " , sizeof ( " this " ) - 1 ) ) {
if ( CG ( active_op_array ) - > scope & &
( CG ( active_op_array ) - > fn_flags & ZEND_ACC_STATIC ) = = 0 ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot re-assign $this " ) ;
2010-04-20 19:16:39 +08:00
}
CG ( active_op_array ) - > this_var = var . u . op . var ;
}
2007-05-04 14:18:53 +08:00
}
2013-09-27 00:39:17 +08:00
if ( CG ( active_op_array ) - > fn_flags & ZEND_ACC_VARIADIC ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Only the last parameter can be variadic " ) ;
2013-09-27 00:39:17 +08:00
}
if ( is_variadic ) {
if ( op = = ZEND_RECV_INIT ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Variadic parameter cannot have a default value " ) ;
2013-09-27 00:39:17 +08:00
}
op = ZEND_RECV_VARIADIC ;
CG ( active_op_array ) - > fn_flags | = ZEND_ACC_VARIADIC ;
}
2007-05-04 14:18:53 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
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
CG ( active_op_array ) - > num_args + + ;
1999-04-08 02:10:10 +08:00
opline - > opcode = op ;
2010-04-20 19:16:39 +08:00
SET_NODE ( opline - > result , & var ) ;
2013-09-27 01:43:32 +08:00
opline - > op1_type = IS_UNUSED ;
opline - > op1 . num = CG ( active_op_array ) - > num_args ;
2004-02-25 17:25:37 +08:00
if ( op = = ZEND_RECV_INIT ) {
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op2 , initialization ) ;
2000-02-02 00:02:38 +08:00
} else {
SET_UNUSED ( opline - > op2 ) ;
2013-09-27 00:39:17 +08:00
if ( ! is_variadic ) {
CG ( active_op_array ) - > required_num_args = CG ( active_op_array ) - > num_args ;
}
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
CG ( active_op_array ) - > arg_info = erealloc ( CG ( active_op_array ) - > arg_info , sizeof ( zend_arg_info ) * ( CG ( active_op_array ) - > num_args ) ) ;
cur_arg_info = & CG ( active_op_array ) - > arg_info [ CG ( active_op_array ) - > num_args - 1 ] ;
2014-02-10 14:04:30 +08:00
cur_arg_info - > name = estrndup ( Z_STRVAL ( varname - > u . constant ) , Z_STRLEN ( varname - > u . constant ) ) ;
2013-09-13 21:07:47 +08:00
cur_arg_info - > name_len = Z_STRLEN ( varname - > u . constant ) ;
2010-05-21 03:18:35 +08:00
cur_arg_info - > type_hint = 0 ;
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
cur_arg_info - > pass_by_reference = pass_by_reference ;
2013-09-27 00:39:17 +08:00
cur_arg_info - > allow_null = 1 ;
cur_arg_info - > is_variadic = is_variadic ;
2007-12-04 20:38:42 +08:00
cur_arg_info - > class_name = NULL ;
2014-02-21 23:02:24 +08:00
cur_arg_info - > class_name_len = 0 ;
2003-05-08 06:19:43 +08:00
if ( class_type - > op_type ! = IS_UNUSED ) {
2005-11-15 23:59:49 +08:00
cur_arg_info - > allow_null = 0 ;
2010-05-21 03:18:35 +08:00
2014-04-02 18:34:44 +08:00
if ( Z_TYPE ( class_type - > u . constant ) ! = IS_NULL ) {
if ( Z_TYPE ( class_type - > u . constant ) = = IS_ARRAY ) {
2011-08-16 18:44:47 +08:00
cur_arg_info - > type_hint = IS_ARRAY ;
if ( op = = ZEND_RECV_INIT ) {
2013-10-31 15:57:12 +08:00
if ( Z_TYPE ( initialization - > u . constant ) = = IS_NULL | | ( Z_TYPE ( initialization - > u . constant ) = = IS_CONSTANT & & ! strcasecmp ( Z_STRVAL ( initialization - > u . constant ) , " NULL " ) ) | | Z_TYPE ( initialization - > u . constant ) = = IS_CONSTANT_AST ) {
2011-08-16 18:44:47 +08:00
cur_arg_info - > allow_null = 1 ;
2014-05-07 19:03:56 +08:00
} else if ( Z_TYPE ( initialization - > u . constant ) ! = IS_ARRAY ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Default value for parameters with array type hint can only be an array or NULL " ) ;
2011-08-16 18:44:47 +08:00
}
2005-11-15 23:59:49 +08:00
}
2014-04-02 18:34:44 +08:00
} else if ( Z_TYPE ( class_type - > u . constant ) = = IS_CALLABLE ) {
2011-08-16 18:44:47 +08:00
cur_arg_info - > type_hint = IS_CALLABLE ;
if ( op = = ZEND_RECV_INIT ) {
2013-10-31 15:57:12 +08:00
if ( Z_TYPE ( initialization - > u . constant ) = = IS_NULL | | ( Z_TYPE ( initialization - > u . constant ) = = IS_CONSTANT & & ! strcasecmp ( Z_STRVAL ( initialization - > u . constant ) , " NULL " ) ) | | Z_TYPE ( initialization - > u . constant ) = = IS_CONSTANT_AST ) {
2011-08-16 18:44:47 +08:00
cur_arg_info - > allow_null = 1 ;
} else {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Default value for parameters with callable type hint can only be NULL " ) ;
2011-08-16 18:44:47 +08:00
}
}
} else {
cur_arg_info - > type_hint = IS_OBJECT ;
if ( ZEND_FETCH_CLASS_DEFAULT = = zend_get_class_fetch_type ( Z_STRVAL ( class_type - > u . constant ) , Z_STRLEN ( class_type - > u . constant ) ) ) {
2013-09-13 18:18:39 +08:00
zend_resolve_class_name ( class_type TSRMLS_CC ) ;
2011-08-16 18:44:47 +08:00
}
2014-02-10 14:04:30 +08:00
Z_STR ( class_type - > u . constant ) = zend_new_interned_string ( Z_STR ( class_type - > u . constant ) TSRMLS_CC ) ;
2014-04-03 19:26:23 +08:00
if ( IS_INTERNED ( Z_STR ( class_type - > u . constant ) ) ) {
Z_TYPE_FLAGS ( class_type - > u . constant ) & = ~ ( IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE ) ;
}
2014-04-15 19:40:40 +08:00
// TODO: for now we have to copy it ???
2014-02-24 17:33:30 +08:00
# if 1
cur_arg_info - > class_name = estrndup ( Z_STRVAL ( class_type - > u . constant ) , Z_STRLEN ( class_type - > u . constant ) ) ;
cur_arg_info - > class_name_len = Z_STRLEN ( class_type - > u . constant ) ;
STR_RELEASE ( Z_STR ( class_type - > u . constant ) ) ;
# else
2014-02-21 23:02:24 +08:00
cur_arg_info - > class_name = Z_STRVAL ( class_type - > u . constant ) ;
cur_arg_info - > class_name_len = Z_STRLEN ( class_type - > u . constant ) ;
2014-02-24 17:33:30 +08:00
# endif
2011-08-16 18:44:47 +08:00
if ( op = = ZEND_RECV_INIT ) {
2013-10-31 15:57:12 +08:00
if ( Z_TYPE ( initialization - > u . constant ) = = IS_NULL | | ( Z_TYPE ( initialization - > u . constant ) = = IS_CONSTANT & & ! strcasecmp ( Z_STRVAL ( initialization - > u . constant ) , " NULL " ) ) | | Z_TYPE ( initialization - > u . constant ) = = IS_CONSTANT_AST ) {
2011-08-16 18:44:47 +08:00
cur_arg_info - > allow_null = 1 ;
} else {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Default value for parameters with a class type hint can only be NULL " ) ;
2011-08-16 18:44:47 +08:00
}
2005-11-16 00:49:40 +08:00
}
}
2005-05-26 21:46:17 +08:00
}
2003-03-06 22:31:17 +08:00
}
2014-04-04 18:36:34 +08:00
if ( cur_arg_info - > class_name | | cur_arg_info - > type_hint ) {
CG ( active_op_array ) - > fn_flags | = ZEND_ACC_HAS_TYPE_HINTS ;
}
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
int zend_do_begin_function_call ( znode * function_name , zend_bool check_namespace TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
zend_function * function ;
2014-02-10 14:04:30 +08:00
zend_string * lcname ;
2008-11-12 03:45:29 +08:00
char * is_compound = memchr ( Z_STRVAL ( function_name - > u . constant ) , ' \\ ' , Z_STRLEN ( function_name - > u . constant ) ) ;
2007-09-29 03:52:53 +08:00
2013-08-30 23:55:43 +08:00
zend_resolve_function_name ( function_name , & check_namespace TSRMLS_CC ) ;
2007-09-29 03:52:53 +08:00
2014-02-10 14:04:30 +08:00
if ( check_namespace & & Z_TYPE ( CG ( current_namespace ) ) ! = IS_UNDEF & & ! is_compound ) {
2008-11-04 23:58:55 +08:00
/* We assume we call function from the current namespace
if it is not prefixed . */
2007-09-29 03:52:53 +08:00
2008-11-04 23:58:55 +08:00
/* In run-time PHP will check for function with full name and
internal function with short name */
2008-11-12 03:45:29 +08:00
zend_do_begin_dynamic_function_call ( function_name , 1 TSRMLS_CC ) ;
return 1 ;
2013-01-28 10:02:51 +08:00
}
2008-11-12 03:45:29 +08:00
2014-02-10 14:04:30 +08:00
lcname = STR_ALLOC ( Z_STRLEN ( function_name - > u . constant ) , 0 ) ;
zend_str_tolower_copy ( lcname - > val , Z_STRVAL ( function_name - > u . constant ) , Z_STRLEN ( function_name - > u . constant ) ) ;
if ( ( ( function = zend_hash_find_ptr ( CG ( function_table ) , lcname ) ) = = NULL ) | |
2008-11-12 03:45:29 +08:00
( ( CG ( compiler_options ) & ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS ) & &
( function - > type = = ZEND_INTERNAL_FUNCTION ) ) ) {
zend_do_begin_dynamic_function_call ( function_name , 0 TSRMLS_CC ) ;
efree ( lcname ) ;
return 1 ; /* Dynamic */
2013-01-28 10:02:51 +08:00
}
2014-02-10 14:04:30 +08:00
STR_RELEASE ( Z_STR ( function_name - > u . constant ) ) ;
Z_STR ( function_name - > u . constant ) = lcname ;
2013-01-28 10:02:51 +08:00
2014-02-26 06:39:50 +08:00
zend_push_function_call_entry ( function TSRMLS_CC ) ;
2012-11-30 17:39:23 +08:00
if ( CG ( context ) . nested_calls + 1 > CG ( active_op_array ) - > nested_calls ) {
CG ( active_op_array ) - > nested_calls = CG ( context ) . nested_calls + 1 ;
}
2006-05-10 07:53:23 +08:00
zend_do_extended_fcall_begin ( TSRMLS_C ) ;
1999-07-29 20:24:58 +08:00
return 0 ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_begin_method_call ( znode * left_bracket TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2001-09-07 22:46:12 +08:00
zend_op * last_op ;
int last_op_number ;
2000-07-04 03:17:57 +08:00
2008-05-07 20:04:39 +08:00
zend_do_end_variable_parse ( left_bracket , BP_VAR_R , 0 TSRMLS_CC ) ;
2001-08-08 23:07:11 +08:00
zend_do_begin_variable_parse ( TSRMLS_C ) ;
2006-05-10 07:53:23 +08:00
2001-09-07 22:46:12 +08:00
last_op_number = get_next_op_number ( CG ( active_op_array ) ) - 1 ;
last_op = & CG ( active_op_array ) - > opcodes [ last_op_number ] ;
2001-12-27 01:49:22 +08:00
2010-04-20 18:57:45 +08:00
if ( ( last_op - > op2_type = = IS_CONST ) & & ( Z_TYPE ( CONSTANT ( last_op - > op2 . constant ) ) = = IS_STRING ) & & ( Z_STRLEN ( CONSTANT ( last_op - > op2 . constant ) ) = = sizeof ( ZEND_CLONE_FUNC_NAME ) - 1 )
& & ! zend_binary_strcasecmp ( Z_STRVAL ( CONSTANT ( last_op - > op2 . constant ) ) , Z_STRLEN ( CONSTANT ( last_op - > op2 . constant ) ) , ZEND_CLONE_FUNC_NAME , sizeof ( ZEND_CLONE_FUNC_NAME ) - 1 ) ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot call __clone() method on objects - use 'clone $obj' instead " ) ;
2001-12-27 01:49:22 +08:00
}
2002-01-04 16:07:39 +08:00
2003-12-17 22:45:59 +08:00
if ( last_op - > opcode = = ZEND_FETCH_OBJ_R ) {
2010-04-20 18:57:45 +08:00
if ( last_op - > op2_type = = IS_CONST ) {
2010-05-24 22:11:39 +08:00
zval name ;
name = CONSTANT ( last_op - > op2 . constant ) ;
2011-12-27 16:38:18 +08:00
if ( Z_TYPE ( name ) ! = IS_STRING ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Method name must be a string " ) ;
2013-01-28 10:02:51 +08:00
}
2014-04-01 21:10:15 +08:00
Z_STR ( name ) = STR_COPY ( Z_STR ( name ) ) ;
2010-05-24 22:11:39 +08:00
FREE_POLYMORPHIC_CACHE_SLOT ( last_op - > op2 . constant ) ;
2010-04-21 22:58:33 +08:00
last_op - > op2 . constant =
2010-05-24 22:11:39 +08:00
zend_add_func_name_literal ( CG ( active_op_array ) , & name TSRMLS_CC ) ;
GET_POLYMORPHIC_CACHE_SLOT ( last_op - > op2 . constant ) ;
2010-04-20 18:57:45 +08:00
}
2003-12-17 22:45:59 +08:00
last_op - > opcode = ZEND_INIT_METHOD_CALL ;
2012-11-30 17:39:23 +08:00
last_op - > result_type = IS_UNUSED ;
last_op - > result . num = CG ( context ) . nested_calls ;
2006-05-10 07:53:23 +08:00
Z_LVAL ( left_bracket - > u . constant ) = ZEND_INIT_FCALL_BY_NAME ;
2003-12-17 22:45:59 +08:00
} else {
2004-02-02 20:28:19 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
2003-12-17 22:45:59 +08:00
opline - > opcode = ZEND_INIT_FCALL_BY_NAME ;
2012-11-30 17:39:23 +08:00
opline - > result . num = CG ( context ) . nested_calls ;
2010-04-27 20:09:13 +08:00
SET_UNUSED ( opline - > op1 ) ;
if ( left_bracket - > op_type = = IS_CONST ) {
opline - > op2_type = IS_CONST ;
opline - > op2 . constant = zend_add_func_name_literal ( CG ( active_op_array ) , & left_bracket - > u . constant TSRMLS_CC ) ;
2010-05-24 22:11:39 +08:00
GET_CACHE_SLOT ( opline - > op2 . constant ) ;
2010-04-27 20:17:32 +08:00
} else {
2010-04-27 20:09:13 +08:00
SET_NODE ( opline - > op2 , left_bracket ) ;
2010-04-27 20:17:32 +08:00
}
2003-12-17 22:45:59 +08:00
}
2001-08-08 23:07:11 +08:00
2014-02-26 06:39:50 +08:00
zend_push_function_call_entry ( NULL TSRMLS_CC ) ;
2012-11-30 17:39:23 +08:00
if ( + + CG ( context ) . nested_calls > CG ( active_op_array ) - > nested_calls ) {
CG ( active_op_array ) - > nested_calls = CG ( context ) . nested_calls ;
}
2006-05-10 07:53:23 +08:00
zend_do_extended_fcall_begin ( TSRMLS_C ) ;
2001-08-08 23:07:11 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2006-05-10 07:53:23 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_clone ( znode * result , znode * expr TSRMLS_DC ) /* { { { */
2004-02-02 20:28:19 +08:00
{
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
opline - > opcode = ZEND_CLONE ;
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op1 , expr ) ;
2004-02-02 20:28:19 +08:00
SET_UNUSED ( opline - > op2 ) ;
2010-04-20 18:57:45 +08:00
opline - > result_type = IS_VAR ;
opline - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
GET_NODE ( result , opline - > result ) ;
2004-02-02 20:28:19 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2004-02-02 20:28:19 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_begin_dynamic_function_call ( znode * function_name , int ns_call TSRMLS_DC ) /* { { { */
2001-08-08 23:07:11 +08:00
{
2010-04-27 20:09:13 +08:00
zend_op * opline ;
2001-08-08 23:07:11 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
2008-11-12 03:45:29 +08:00
if ( ns_call ) {
2007-09-29 03:52:53 +08:00
/* In run-time PHP will check for function with full name and
internal function with short name */
2007-11-22 17:02:55 +08:00
opline - > opcode = ZEND_INIT_NS_FCALL_BY_NAME ;
2012-11-30 17:39:23 +08:00
opline - > result . num = CG ( context ) . nested_calls ;
2010-04-27 20:09:13 +08:00
SET_UNUSED ( opline - > op1 ) ;
opline - > op2_type = IS_CONST ;
opline - > op2 . constant = zend_add_ns_func_name_literal ( CG ( active_op_array ) , & function_name - > u . constant TSRMLS_CC ) ;
2010-05-24 22:11:39 +08:00
GET_CACHE_SLOT ( opline - > op2 . constant ) ;
2007-09-29 03:52:53 +08:00
} else {
2007-11-22 17:02:55 +08:00
opline - > opcode = ZEND_INIT_FCALL_BY_NAME ;
2012-11-30 17:39:23 +08:00
opline - > result . num = CG ( context ) . nested_calls ;
2010-04-27 20:09:13 +08:00
SET_UNUSED ( opline - > op1 ) ;
if ( function_name - > op_type = = IS_CONST ) {
opline - > op2_type = IS_CONST ;
opline - > op2 . constant = zend_add_func_name_literal ( CG ( active_op_array ) , & function_name - > u . constant TSRMLS_CC ) ;
2010-05-24 22:11:39 +08:00
GET_CACHE_SLOT ( opline - > op2 . constant ) ;
2010-04-27 20:17:32 +08:00
} else {
2010-04-27 20:09:13 +08:00
SET_NODE ( opline - > op2 , function_name ) ;
2010-04-27 20:17:32 +08:00
}
2007-09-29 03:52:53 +08:00
}
2001-08-08 23:07:11 +08:00
2014-02-26 06:39:50 +08:00
zend_push_function_call_entry ( NULL TSRMLS_CC ) ;
2012-11-30 17:39:23 +08:00
if ( + + CG ( context ) . nested_calls > CG ( active_op_array ) - > nested_calls ) {
CG ( active_op_array ) - > nested_calls = CG ( context ) . nested_calls ;
}
2006-05-10 07:53:23 +08:00
zend_do_extended_fcall_begin ( TSRMLS_C ) ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2013-08-30 23:55:43 +08:00
void zend_resolve_non_class_name ( znode * element_name , zend_bool * check_namespace , zend_bool case_sensitive , HashTable * current_import_sub TSRMLS_DC ) /* { { { */
2008-11-04 23:58:55 +08:00
{
znode tmp ;
int len ;
2014-02-10 14:04:30 +08:00
zval * ns ;
zend_string * lookup_name ;
char * compound = memchr ( Z_STRVAL ( element_name - > u . constant ) , ' \\ ' , Z_STRLEN ( element_name - > u . constant ) ) ;
2008-11-04 23:58:55 +08:00
if ( Z_STRVAL ( element_name - > u . constant ) [ 0 ] = = ' \\ ' ) {
2008-11-12 03:45:29 +08:00
/* name starts with \ so it is known and unambiguos, nothing to do here but shorten it */
memmove ( Z_STRVAL ( element_name - > u . constant ) , Z_STRVAL ( element_name - > u . constant ) + 1 , Z_STRLEN ( element_name - > u . constant ) ) ;
- - Z_STRLEN ( element_name - > u . constant ) ;
return ;
}
2013-08-30 23:55:43 +08:00
if ( ! * check_namespace ) {
2008-11-12 03:45:29 +08:00
return ;
2008-11-04 23:58:55 +08:00
}
2013-07-24 03:08:49 +08:00
if ( current_import_sub ) {
2014-02-19 18:35:28 +08:00
len = Z_STRLEN ( element_name - > u . constant ) ;
2013-08-25 22:21:51 +08:00
if ( case_sensitive ) {
2014-02-10 14:04:30 +08:00
lookup_name = STR_INIT ( Z_STRVAL ( element_name - > u . constant ) , len , 0 ) ;
2013-08-25 22:21:51 +08:00
} else {
2014-02-10 14:04:30 +08:00
lookup_name = STR_ALLOC ( len , 0 ) ;
zend_str_tolower_copy ( lookup_name - > val , Z_STRVAL ( element_name - > u . constant ) , len ) ;
2013-08-25 22:21:51 +08:00
}
2013-07-24 02:21:48 +08:00
/* Check if function/const matches imported name */
2014-02-10 14:04:30 +08:00
if ( ( ns = zend_hash_find ( current_import_sub , lookup_name ) ) ! = NULL ) {
2013-07-17 02:39:33 +08:00
zval_dtor ( & element_name - > u . constant ) ;
2014-02-19 18:35:28 +08:00
ZVAL_DUP ( & element_name - > u . constant , ns ) ;
2014-02-10 14:04:30 +08:00
STR_FREE ( lookup_name ) ;
2013-08-30 23:55:43 +08:00
* check_namespace = 0 ;
2013-07-17 02:39:33 +08:00
return ;
}
2014-02-10 14:04:30 +08:00
STR_FREE ( lookup_name ) ;
2013-07-17 02:39:33 +08:00
}
2008-11-12 03:45:29 +08:00
if ( compound & & CG ( current_import ) ) {
len = compound - Z_STRVAL ( element_name - > u . constant ) ;
2013-09-19 16:51:57 +08:00
/* namespace is always lowercase */
2014-02-10 14:04:30 +08:00
lookup_name = STR_ALLOC ( len , 0 ) ;
zend_str_tolower_copy ( lookup_name - > val , Z_STRVAL ( element_name - > u . constant ) , len ) ;
2008-11-04 23:58:55 +08:00
/* Check if first part of compound name is an import name */
2014-02-10 14:04:30 +08:00
if ( ( ns = zend_hash_find ( CG ( current_import ) , lookup_name ) ) ! = NULL ) {
2008-11-04 23:58:55 +08:00
/* Substitute import name */
tmp . op_type = IS_CONST ;
2014-02-10 14:04:30 +08:00
ZVAL_DUP ( & tmp . u . constant , ns ) ;
2008-11-04 23:58:55 +08:00
len + = 1 ;
Z_STRLEN ( element_name - > u . constant ) - = len ;
memmove ( Z_STRVAL ( element_name - > u . constant ) , Z_STRVAL ( element_name - > u . constant ) + len , Z_STRLEN ( element_name - > u . constant ) + 1 ) ;
zend_do_build_namespace_name ( & tmp , & tmp , element_name TSRMLS_CC ) ;
2008-11-12 03:45:29 +08:00
* element_name = tmp ;
2014-02-10 14:04:30 +08:00
STR_FREE ( lookup_name ) ;
2013-08-30 23:55:43 +08:00
* check_namespace = 0 ;
2008-11-04 23:58:55 +08:00
return ;
}
2014-02-10 14:04:30 +08:00
STR_FREE ( lookup_name ) ;
2008-11-04 23:58:55 +08:00
}
2014-02-10 14:04:30 +08:00
if ( Z_TYPE ( CG ( current_namespace ) ) ! = IS_UNDEF ) {
2008-11-04 23:58:55 +08:00
tmp = * element_name ;
2014-02-10 14:04:30 +08:00
Z_STR ( tmp . u . constant ) = STR_ALLOC ( sizeof ( " \\ " ) - 1 + Z_STRLEN ( element_name - > u . constant ) + Z_STRLEN ( CG ( current_namespace ) ) , 0 ) ;
2014-04-03 19:26:23 +08:00
Z_TYPE_FLAGS ( tmp . u . constant ) = IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE ;
2014-02-10 14:04:30 +08:00
memcpy ( Z_STRVAL ( tmp . u . constant ) , Z_STRVAL ( CG ( current_namespace ) ) , Z_STRLEN ( CG ( current_namespace ) ) ) ;
memcpy ( & ( Z_STRVAL ( tmp . u . constant ) [ Z_STRLEN ( CG ( current_namespace ) ) ] ) , " \\ " , sizeof ( " \\ " ) - 1 ) ;
memcpy ( & ( Z_STRVAL ( tmp . u . constant ) [ Z_STRLEN ( CG ( current_namespace ) ) + sizeof ( " \\ " ) - 1 ] ) , Z_STRVAL ( element_name - > u . constant ) , Z_STRLEN ( element_name - > u . constant ) + 1 ) ;
STR_RELEASE ( Z_STR ( element_name - > u . constant ) ) ;
2008-11-04 23:58:55 +08:00
* element_name = tmp ;
}
}
2009-07-27 22:11:53 +08:00
/* }}} */
2008-11-04 23:58:55 +08:00
2013-08-30 23:55:43 +08:00
void zend_resolve_function_name ( znode * element_name , zend_bool * check_namespace TSRMLS_DC ) /* { { { */
2013-07-24 03:08:49 +08:00
{
2013-08-25 22:21:51 +08:00
zend_resolve_non_class_name ( element_name , check_namespace , 0 , CG ( current_import_function ) TSRMLS_CC ) ;
2013-07-24 03:08:49 +08:00
}
/* }}} */
2013-08-30 23:55:43 +08:00
void zend_resolve_const_name ( znode * element_name , zend_bool * check_namespace TSRMLS_DC ) /* { { { */
2013-07-24 03:08:49 +08:00
{
2013-08-25 22:21:51 +08:00
zend_resolve_non_class_name ( element_name , check_namespace , 1 , CG ( current_import_const ) TSRMLS_CC ) ;
2013-07-24 03:08:49 +08:00
}
/* }}} */
2013-01-19 08:00:47 +08:00
void zend_do_resolve_class_name ( znode * result , znode * class_name , int is_static TSRMLS_DC ) /* { { { */
{
char * lcname ;
int lctype ;
znode constant_name ;
2013-09-13 21:07:47 +08:00
lcname = zend_str_tolower_dup ( Z_STRVAL ( class_name - > u . constant ) , Z_STRLEN ( class_name - > u . constant ) ) ;
2013-01-19 08:00:47 +08:00
lctype = zend_get_class_fetch_type ( lcname , strlen ( lcname ) ) ;
switch ( lctype ) {
case ZEND_FETCH_CLASS_SELF :
if ( ! CG ( active_class_entry ) ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot access self::class when no class scope is active " ) ;
2013-01-19 08:00:47 +08:00
}
zval_dtor ( & class_name - > u . constant ) ;
class_name - > op_type = IS_CONST ;
2014-02-10 14:04:30 +08:00
ZVAL_STR ( & class_name - > u . constant , STR_COPY ( CG ( active_class_entry ) - > name ) ) ;
2013-01-19 08:00:47 +08:00
* result = * class_name ;
break ;
case ZEND_FETCH_CLASS_STATIC :
case ZEND_FETCH_CLASS_PARENT :
if ( is_static ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR ,
2013-01-19 08:00:47 +08:00
" %s::class cannot be used for compile-time class name resolution " ,
lctype = = ZEND_FETCH_CLASS_STATIC ? " static " : " parent "
) ;
}
if ( ! CG ( active_class_entry ) ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR ,
2013-01-19 08:00:47 +08:00
" Cannot access %s::class when no class scope is active " ,
lctype = = ZEND_FETCH_CLASS_STATIC ? " static " : " parent "
) ;
}
constant_name . op_type = IS_CONST ;
2014-02-10 14:04:30 +08:00
ZVAL_STRINGL ( & constant_name . u . constant , " class " , sizeof ( " class " ) - 1 ) ;
2013-01-19 08:00:47 +08:00
zend_do_fetch_constant ( result , class_name , & constant_name , ZEND_RT , 1 TSRMLS_CC ) ;
break ;
case ZEND_FETCH_CLASS_DEFAULT :
2013-09-13 18:18:39 +08:00
zend_resolve_class_name ( class_name TSRMLS_CC ) ;
2013-01-19 08:00:47 +08:00
* result = * class_name ;
break ;
}
efree ( lcname ) ;
}
/* }}} */
2013-09-13 18:18:39 +08:00
void zend_resolve_class_name ( znode * class_name TSRMLS_DC ) /* { { { */
2007-09-29 03:52:53 +08:00
{
char * compound ;
2014-02-10 14:04:30 +08:00
zend_string * lcname ;
zval * ns ;
2007-09-29 03:52:53 +08:00
znode tmp ;
int len ;
2008-11-04 23:58:55 +08:00
compound = memchr ( Z_STRVAL ( class_name - > u . constant ) , ' \\ ' , Z_STRLEN ( class_name - > u . constant ) ) ;
2007-09-29 03:52:53 +08:00
if ( compound ) {
2008-11-04 23:58:55 +08:00
/* This is a compound class name that contains namespace prefix */
2008-11-12 03:45:29 +08:00
if ( Z_STRVAL ( class_name - > u . constant ) [ 0 ] = = ' \\ ' ) {
2011-01-20 01:17:52 +08:00
/* The STRING name has "\" prefix */
2014-02-21 22:14:47 +08:00
memmove ( Z_STRVAL ( class_name - > u . constant ) , Z_STRVAL ( class_name - > u . constant ) + 1 , Z_STRLEN ( class_name - > u . constant ) ) ;
2014-02-17 21:59:18 +08:00
Z_STR ( class_name - > u . constant ) = STR_REALLOC (
2014-02-10 14:04:30 +08:00
Z_STR ( class_name - > u . constant ) ,
2014-02-17 21:59:18 +08:00
Z_STRLEN ( class_name - > u . constant ) - 1 , 0 ) ;
2014-04-03 19:26:23 +08:00
Z_TYPE_FLAGS ( class_name - > u . constant ) = IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE ;
2007-12-03 22:15:43 +08:00
if ( ZEND_FETCH_CLASS_DEFAULT ! = zend_get_class_fetch_type ( Z_STRVAL ( class_name - > u . constant ) , Z_STRLEN ( class_name - > u . constant ) ) ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " ' \\ %s' is an invalid class name " , Z_STRVAL ( class_name - > u . constant ) ) ;
2008-11-04 23:58:55 +08:00
}
2013-01-28 10:02:51 +08:00
} else {
2008-11-04 23:58:55 +08:00
if ( CG ( current_import ) ) {
len = compound - Z_STRVAL ( class_name - > u . constant ) ;
2014-02-10 14:04:30 +08:00
lcname = STR_ALLOC ( len , 0 ) ;
zend_str_tolower_copy ( lcname - > val , Z_STRVAL ( class_name - > u . constant ) , len ) ;
2008-11-04 23:58:55 +08:00
/* Check if first part of compound name is an import name */
2014-02-10 14:04:30 +08:00
if ( ( ns = zend_hash_find ( CG ( current_import ) , lcname ) ) ! = NULL ) {
2008-11-04 23:58:55 +08:00
/* Substitute import name */
tmp . op_type = IS_CONST ;
2014-02-10 14:04:30 +08:00
ZVAL_DUP ( & tmp . u . constant , ns ) ;
2008-11-04 23:58:55 +08:00
len + = 1 ;
Z_STRLEN ( class_name - > u . constant ) - = len ;
memmove ( Z_STRVAL ( class_name - > u . constant ) , Z_STRVAL ( class_name - > u . constant ) + len , Z_STRLEN ( class_name - > u . constant ) + 1 ) ;
zend_do_build_namespace_name ( & tmp , & tmp , class_name TSRMLS_CC ) ;
* class_name = tmp ;
2014-02-10 14:04:30 +08:00
STR_FREE ( lcname ) ;
2008-11-12 03:45:29 +08:00
return ;
2008-11-04 23:58:55 +08:00
}
2014-02-10 14:04:30 +08:00
STR_FREE ( lcname ) ;
2007-12-03 22:15:43 +08:00
}
2008-11-12 03:45:29 +08:00
/* Here name is not prefixed with \ and not imported */
2014-02-10 14:04:30 +08:00
if ( Z_TYPE ( CG ( current_namespace ) ) ! = IS_UNDEF ) {
2007-09-29 03:52:53 +08:00
tmp . op_type = IS_CONST ;
2014-02-10 14:04:30 +08:00
ZVAL_DUP ( & tmp . u . constant , & CG ( current_namespace ) ) ;
2007-09-29 03:52:53 +08:00
zend_do_build_namespace_name ( & tmp , & tmp , class_name TSRMLS_CC ) ;
* class_name = tmp ;
}
}
2014-02-10 14:04:30 +08:00
} else if ( CG ( current_import ) | | Z_TYPE ( CG ( current_namespace ) ) ! = IS_UNDEF ) {
2008-11-04 23:58:55 +08:00
/* this is a plain name (without \) */
2014-02-10 14:04:30 +08:00
lcname = STR_ALLOC ( Z_STRLEN ( class_name - > u . constant ) , 0 ) ;
zend_str_tolower_copy ( lcname - > val , Z_STRVAL ( class_name - > u . constant ) , Z_STRLEN ( class_name - > u . constant ) ) ;
2007-09-29 03:52:53 +08:00
if ( CG ( current_import ) & &
2014-02-10 14:04:30 +08:00
( ns = zend_hash_find ( CG ( current_import ) , lcname ) ) ! = NULL ) {
2007-09-29 03:52:53 +08:00
/* The given name is an import name. Substitute it. */
zval_dtor ( & class_name - > u . constant ) ;
2014-02-10 14:04:30 +08:00
ZVAL_DUP ( & class_name - > u . constant , ns ) ;
} else if ( Z_TYPE ( CG ( current_namespace ) ) ! = IS_UNDEF ) {
2008-11-12 03:45:29 +08:00
/* plain name, no import - prepend current namespace to it */
2007-09-29 03:52:53 +08:00
tmp . op_type = IS_CONST ;
2014-02-10 14:04:30 +08:00
ZVAL_DUP ( & tmp . u . constant , & CG ( current_namespace ) ) ;
2007-09-29 03:52:53 +08:00
zend_do_build_namespace_name ( & tmp , & tmp , class_name TSRMLS_CC ) ;
* class_name = tmp ;
}
2014-02-10 14:04:30 +08:00
STR_FREE ( lcname ) ;
2007-09-29 03:52:53 +08:00
}
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_fetch_class ( znode * result , znode * class_name TSRMLS_DC ) /* { { { */
2001-10-30 01:19:02 +08:00
{
2002-01-14 04:21:55 +08:00
long fetch_class_op_number ;
zend_op * opline ;
fetch_class_op_number = get_next_op_number ( CG ( active_op_array ) ) ;
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
2001-10-30 01:19:02 +08:00
opline - > opcode = ZEND_FETCH_CLASS ;
2003-06-02 20:13:11 +08:00
SET_UNUSED ( opline - > op1 ) ;
2013-09-13 18:18:39 +08:00
opline - > extended_value = ZEND_FETCH_CLASS_DEFAULT ;
2003-02-24 21:35:47 +08:00
CG ( catch_begin ) = fetch_class_op_number ;
2003-03-10 06:02:37 +08:00
if ( class_name - > op_type = = IS_CONST ) {
2003-08-03 16:21:08 +08:00
int fetch_type ;
2013-09-13 21:07:47 +08:00
fetch_type = zend_get_class_fetch_type ( Z_STRVAL ( class_name - > u . constant ) , Z_STRLEN ( class_name - > u . constant ) ) ;
2003-08-03 16:21:08 +08:00
switch ( fetch_type ) {
case ZEND_FETCH_CLASS_SELF :
case ZEND_FETCH_CLASS_PARENT :
2007-09-29 15:28:34 +08:00
case ZEND_FETCH_CLASS_STATIC :
2003-08-03 16:21:08 +08:00
SET_UNUSED ( opline - > op2 ) ;
opline - > extended_value = fetch_type ;
zval_dtor ( & class_name - > u . constant ) ;
break ;
default :
2013-09-13 18:18:39 +08:00
zend_resolve_class_name ( class_name TSRMLS_CC ) ;
2010-04-21 22:58:33 +08:00
opline - > op2_type = IS_CONST ;
opline - > op2 . constant =
2010-04-21 23:08:10 +08:00
zend_add_class_name_literal ( CG ( active_op_array ) , & class_name - > u . constant TSRMLS_CC ) ;
2003-08-03 16:21:08 +08:00
break ;
2003-03-05 21:25:33 +08:00
}
} else {
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op2 , class_name ) ;
2001-12-13 01:38:37 +08:00
}
2010-04-20 18:57:45 +08:00
opline - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
opline - > result_type = IS_VAR ; /* FIXME: Hack so that INIT_FCALL_BY_NAME still knows this is a class */
GET_NODE ( result , opline - > result ) ;
result - > EA = opline - > extended_value ;
2001-10-30 01:19:02 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2001-10-30 01:19:02 +08:00
2014-02-19 18:35:28 +08:00
static void ptr_dtor ( zval * zv ) /* { { { */
2014-02-19 05:12:05 +08:00
{
efree ( Z_PTR_P ( zv ) ) ;
}
/* }}} */
2008-03-28 22:35:01 +08:00
void zend_do_label ( znode * label TSRMLS_DC ) /* { { { */
{
zend_label dest ;
2010-09-15 15:38:52 +08:00
if ( ! CG ( context ) . labels ) {
ALLOC_HASHTABLE ( CG ( context ) . labels ) ;
2014-04-21 22:25:34 +08:00
zend_hash_init ( CG ( context ) . labels , 8 , NULL , ptr_dtor , 0 ) ;
2008-03-28 22:35:01 +08:00
}
2010-09-15 15:38:52 +08:00
dest . brk_cont = CG ( context ) . current_brk_cont ;
dest . opline_num = get_next_op_number ( CG ( active_op_array ) ) ;
2008-03-28 22:35:01 +08:00
2014-02-10 14:04:30 +08:00
if ( zend_hash_add_mem ( CG ( context ) . labels , Z_STR ( label - > u . constant ) , & dest , sizeof ( zend_label ) ) = = NULL ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Label '%s' already defined " , Z_STRVAL ( label - > u . constant ) ) ;
2008-03-28 22:35:01 +08:00
}
/* Done with label now */
zval_dtor ( & label - > u . constant ) ;
}
/* }}} */
void zend_resolve_goto_label ( zend_op_array * op_array , zend_op * opline , int pass2 TSRMLS_DC ) /* { { { */
{
zend_label * dest ;
long current , distance ;
2010-04-20 18:57:45 +08:00
zval * label ;
2008-03-28 22:35:01 +08:00
2010-04-20 18:57:45 +08:00
if ( pass2 ) {
label = opline - > op2 . zv ;
} else {
label = & CONSTANT_EX ( op_array , opline - > op2 . constant ) ;
}
2010-09-15 15:38:52 +08:00
if ( CG ( context ) . labels = = NULL | |
2014-02-10 14:04:30 +08:00
( dest = zend_hash_find_ptr ( CG ( context ) . labels , Z_STR_P ( label ) ) ) = = NULL ) {
2008-03-28 22:35:01 +08:00
2011-01-20 01:17:52 +08:00
if ( pass2 ) {
CG ( in_compilation ) = 1 ;
CG ( active_op_array ) = op_array ;
CG ( zend_lineno ) = opline - > lineno ;
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " 'goto' to undefined label '%s' " , Z_STRVAL_P ( label ) ) ;
2011-01-20 01:17:52 +08:00
} else {
2008-03-28 22:35:01 +08:00
/* Label is not defined. Delay to pass 2. */
INC_BPC ( op_array ) ;
return ;
}
}
2010-04-20 18:57:45 +08:00
opline - > op1 . opline_num = dest - > opline_num ;
zval_dtor ( label ) ;
2014-04-03 19:26:23 +08:00
ZVAL_NULL ( label ) ;
2008-03-28 22:35:01 +08:00
/* Check that we are not moving into loop or switch */
current = opline - > extended_value ;
for ( distance = 0 ; current ! = dest - > brk_cont ; distance + + ) {
if ( current = = - 1 ) {
2011-01-20 01:17:52 +08:00
if ( pass2 ) {
CG ( in_compilation ) = 1 ;
CG ( active_op_array ) = op_array ;
CG ( zend_lineno ) = opline - > lineno ;
}
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " 'goto' into loop or switch statement is disallowed " ) ;
2008-03-28 22:35:01 +08:00
}
current = op_array - > brk_cont_array [ current ] . parent ;
}
if ( distance = = 0 ) {
/* Nothing to break out of, optimize to ZEND_JMP */
opline - > opcode = ZEND_JMP ;
opline - > extended_value = 0 ;
SET_UNUSED ( opline - > op2 ) ;
} else {
/* Set real break distance */
2010-04-20 18:57:45 +08:00
ZVAL_LONG ( label , distance ) ;
2008-03-28 22:35:01 +08:00
}
2011-01-20 01:17:52 +08:00
if ( pass2 ) {
2008-03-28 22:35:01 +08:00
DEC_BPC ( op_array ) ;
2011-01-20 01:17:52 +08:00
}
2008-03-28 22:35:01 +08:00
}
/* }}} */
2014-04-22 22:52:59 +08:00
void zend_do_goto ( znode * label TSRMLS_DC ) /* { { { */
2008-03-28 22:35:01 +08:00
{
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
opline - > opcode = ZEND_GOTO ;
2010-09-15 15:38:52 +08:00
opline - > extended_value = CG ( context ) . current_brk_cont ;
2008-03-28 22:35:01 +08:00
SET_UNUSED ( opline - > op1 ) ;
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op2 , label ) ;
2008-03-28 22:35:01 +08:00
zend_resolve_goto_label ( CG ( active_op_array ) , opline , 0 TSRMLS_CC ) ;
}
/* }}} */
2013-03-28 04:03:40 +08:00
void zend_release_labels ( int temporary TSRMLS_DC ) /* { { { */
2008-03-28 22:35:01 +08:00
{
2010-09-15 15:38:52 +08:00
if ( CG ( context ) . labels ) {
zend_hash_destroy ( CG ( context ) . labels ) ;
FREE_HASHTABLE ( CG ( context ) . labels ) ;
2013-03-28 04:03:40 +08:00
CG ( context ) . labels = NULL ;
2008-03-28 22:35:01 +08:00
}
2013-03-28 04:03:40 +08:00
if ( ! temporary & & ! zend_stack_is_empty ( & CG ( context_stack ) ) ) {
2014-05-01 02:48:02 +08:00
zend_compiler_context * ctx = zend_stack_top ( & CG ( context_stack ) ) ;
2010-09-15 15:38:52 +08:00
CG ( context ) = * ctx ;
zend_stack_del_top ( & CG ( context_stack ) ) ;
2008-03-28 22:35:01 +08:00
}
}
/* }}} */
2001-12-01 00:29:47 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_build_full_name ( znode * result , znode * prefix , znode * name , int is_class_member TSRMLS_DC ) /* { { { */
2001-12-01 00:29:47 +08:00
{
zend_uint length ;
if ( ! result ) {
2008-03-26 02:08:37 +08:00
result = prefix ;
2001-12-01 00:29:47 +08:00
} else {
2008-03-26 02:08:37 +08:00
* result = * prefix ;
2001-12-01 00:29:47 +08:00
}
2002-07-16 02:09:56 +08:00
2008-11-04 23:58:55 +08:00
if ( is_class_member ) {
2014-02-10 14:04:30 +08:00
int old_len = Z_STRLEN ( result - > u . constant ) ;
length = sizeof ( " :: " ) - 1 + old_len + Z_STRLEN ( name - > u . constant ) ;
2014-02-17 21:59:18 +08:00
Z_STR ( result - > u . constant ) = STR_REALLOC ( Z_STR ( result - > u . constant ) , length , 0 ) ;
2014-04-03 19:26:23 +08:00
Z_TYPE_FLAGS ( result - > u . constant ) = IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE ;
2014-02-10 14:04:30 +08:00
memcpy ( & Z_STRVAL ( result - > u . constant ) [ old_len ] , " :: " , sizeof ( " :: " ) - 1 ) ;
memcpy ( & Z_STRVAL ( result - > u . constant ) [ old_len + sizeof ( " :: " ) - 1 ] , Z_STRVAL ( name - > u . constant ) , Z_STRLEN ( name - > u . constant ) + 1 ) ;
STR_RELEASE ( Z_STR ( name - > u . constant ) ) ;
2008-11-04 23:58:55 +08:00
} else {
2014-02-10 14:04:30 +08:00
int old_len = Z_STRLEN ( result - > u . constant ) ;
length = sizeof ( " \\ " ) - 1 + old_len + Z_STRLEN ( name - > u . constant ) ;
2014-02-17 21:59:18 +08:00
Z_STR ( result - > u . constant ) = STR_REALLOC ( Z_STR ( result - > u . constant ) , length , 0 ) ;
2014-04-03 19:26:23 +08:00
Z_TYPE_FLAGS ( result - > u . constant ) = IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE ;
2014-02-10 14:04:30 +08:00
memcpy ( & Z_STRVAL ( result - > u . constant ) [ old_len ] , " \\ " , sizeof ( " \\ " ) - 1 ) ;
memcpy ( & Z_STRVAL ( result - > u . constant ) [ old_len + sizeof ( " \\ " ) - 1 ] , Z_STRVAL ( name - > u . constant ) , Z_STRLEN ( name - > u . constant ) + 1 ) ;
STR_RELEASE ( Z_STR ( name - > u . constant ) ) ;
2008-11-04 23:58:55 +08:00
}
2001-12-01 00:29:47 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2001-12-01 00:29:47 +08:00
2009-07-27 22:11:53 +08:00
int zend_do_begin_class_member_function_call ( znode * class_name , znode * method_name TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2007-09-29 03:52:53 +08:00
znode class_node ;
zend_op * opline ;
2004-09-16 08:40:38 +08:00
2007-09-29 03:52:53 +08:00
if ( method_name - > op_type = = IS_CONST ) {
2011-12-27 16:38:18 +08:00
char * lcname ;
2011-12-28 14:46:12 +08:00
if ( Z_TYPE ( method_name - > u . constant ) ! = IS_STRING ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Method name must be a string " ) ;
2011-12-27 16:38:18 +08:00
}
lcname = zend_str_tolower_dup ( Z_STRVAL ( method_name - > u . constant ) , Z_STRLEN ( method_name - > u . constant ) ) ;
2007-09-29 03:52:53 +08:00
if ( ( sizeof ( ZEND_CONSTRUCTOR_FUNC_NAME ) - 1 ) = = Z_STRLEN ( method_name - > u . constant ) & &
2007-03-12 21:10:40 +08:00
memcmp ( lcname , ZEND_CONSTRUCTOR_FUNC_NAME , sizeof ( ZEND_CONSTRUCTOR_FUNC_NAME ) - 1 ) = = 0 ) {
2007-09-29 03:52:53 +08:00
zval_dtor ( & method_name - > u . constant ) ;
2010-04-20 18:57:45 +08:00
method_name - > op_type = IS_UNUSED ;
2003-10-09 21:44:44 +08:00
}
2008-06-04 02:11:12 +08:00
efree ( lcname ) ;
2003-07-03 20:03:11 +08:00
}
2002-01-04 16:07:39 +08:00
2007-09-29 03:52:53 +08:00
if ( class_name - > op_type = = IS_CONST & &
ZEND_FETCH_CLASS_DEFAULT = = zend_get_class_fetch_type ( Z_STRVAL ( class_name - > u . constant ) , Z_STRLEN ( class_name - > u . constant ) ) ) {
2013-09-13 18:18:39 +08:00
zend_resolve_class_name ( class_name TSRMLS_CC ) ;
2007-09-29 03:52:53 +08:00
class_node = * class_name ;
2010-04-20 18:57:45 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
2007-09-29 03:52:53 +08:00
} else {
zend_do_fetch_class ( & class_node , class_name TSRMLS_CC ) ;
2010-04-20 18:57:45 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
opline - > extended_value = class_node . EA ;
2007-09-29 03:52:53 +08:00
}
opline - > opcode = ZEND_INIT_STATIC_METHOD_CALL ;
2012-11-30 17:39:23 +08:00
opline - > result . num = CG ( context ) . nested_calls ;
2010-04-21 22:58:33 +08:00
if ( class_node . op_type = = IS_CONST ) {
opline - > op1_type = IS_CONST ;
opline - > op1 . constant =
2010-04-21 23:08:10 +08:00
zend_add_class_name_literal ( CG ( active_op_array ) , & class_node . u . constant TSRMLS_CC ) ;
2010-04-21 22:58:33 +08:00
} else {
SET_NODE ( opline - > op1 , & class_node ) ;
2010-04-20 18:57:45 +08:00
}
2010-04-21 22:58:33 +08:00
if ( method_name - > op_type = = IS_CONST ) {
opline - > op2_type = IS_CONST ;
opline - > op2 . constant =
2010-04-21 23:08:10 +08:00
zend_add_func_name_literal ( CG ( active_op_array ) , & method_name - > u . constant TSRMLS_CC ) ;
2010-05-24 22:11:39 +08:00
if ( opline - > op1_type = = IS_CONST ) {
GET_CACHE_SLOT ( opline - > op2 . constant ) ;
} else {
GET_POLYMORPHIC_CACHE_SLOT ( opline - > op2 . constant ) ;
}
2010-04-21 22:58:33 +08:00
} else {
SET_NODE ( opline - > op2 , method_name ) ;
2010-04-20 18:57:45 +08:00
}
2007-09-29 03:52:53 +08:00
2014-02-26 06:39:50 +08:00
zend_push_function_call_entry ( NULL TSRMLS_CC ) ;
2012-11-30 17:39:23 +08:00
if ( + + CG ( context ) . nested_calls > CG ( active_op_array ) - > nested_calls ) {
CG ( active_op_array ) - > nested_calls = CG ( context ) . nested_calls ;
}
2004-09-16 08:40:38 +08:00
zend_do_extended_fcall_begin ( TSRMLS_C ) ;
2007-11-20 16:53:02 +08:00
return 1 ; /* Dynamic */
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-02-26 07:14:50 +08:00
void zend_do_end_function_call ( znode * function_name , znode * result , int is_method , int is_dynamic_fcall TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2001-12-27 01:49:22 +08:00
zend_op * opline ;
2014-05-01 02:48:02 +08:00
zend_function_call_entry * fcall = zend_stack_top ( & CG ( function_call_stack ) ) ;
2006-05-10 07:53:23 +08:00
2003-07-01 04:22:35 +08:00
if ( is_method & & function_name & & function_name - > op_type = = IS_UNUSED ) {
2003-05-20 01:12:56 +08:00
/* clone */
2014-02-26 07:14:50 +08:00
if ( fcall - > arg_num ! = 0 ) {
2003-05-20 01:12:56 +08:00
zend_error ( E_WARNING , " Clone method does not require arguments " ) ;
}
2006-05-10 07:53:23 +08:00
opline = & CG ( active_op_array ) - > opcodes [ Z_LVAL ( function_name - > u . constant ) ] ;
1999-06-09 02:33:31 +08:00
} else {
2003-05-20 01:12:56 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
2014-02-26 06:39:50 +08:00
if ( fcall - > fbc ) {
2003-05-20 01:12:56 +08:00
opline - > opcode = ZEND_DO_FCALL ;
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op1 , function_name ) ;
2012-11-30 17:39:23 +08:00
SET_UNUSED ( opline - > op2 ) ;
opline - > op2 . num = CG ( context ) . nested_calls ;
2010-05-24 22:11:39 +08:00
GET_CACHE_SLOT ( opline - > op1 . constant ) ;
2003-05-20 01:12:56 +08:00
} else {
opline - > opcode = ZEND_DO_FCALL_BY_NAME ;
SET_UNUSED ( opline - > op1 ) ;
2012-11-30 17:39:23 +08:00
SET_UNUSED ( opline - > op2 ) ;
opline - > op2 . num = - - CG ( context ) . nested_calls ;
2013-08-29 17:35:11 +08:00
/* This would normally be a ZEND_DO_FCALL, but was forced to use
* ZEND_DO_FCALL_BY_NAME due to a . . . argument . In this case we need to
* free the function_name */
if ( ! is_method & & ! is_dynamic_fcall & & function_name - > op_type = = IS_CONST ) {
zval_dtor ( & function_name - > u . constant ) ;
}
2003-05-20 01:12:56 +08:00
}
1999-06-09 02:33:31 +08:00
}
2006-05-10 07:53:23 +08:00
2010-04-20 18:57:45 +08:00
opline - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
opline - > result_type = IS_VAR ;
2012-11-30 17:39:23 +08:00
GET_NODE ( result , opline - > result ) ;
2014-02-26 07:14:50 +08:00
opline - > extended_value = fcall - > arg_num ;
2012-11-30 17:39:23 +08:00
if ( CG ( context ) . used_stack + 1 > CG ( active_op_array ) - > used_stack ) {
CG ( active_op_array ) - > used_stack = CG ( context ) . used_stack + 1 ;
}
2014-02-26 07:14:50 +08:00
CG ( context ) . used_stack - = fcall - > arg_num ;
zend_stack_del_top ( & CG ( function_call_stack ) ) ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-02-26 07:14:50 +08:00
void zend_do_pass_param ( znode * param , zend_uchar op TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
1999-09-22 04:00:01 +08:00
zend_op * opline ;
2013-08-29 02:12:54 +08:00
int original_op = op ;
2014-05-01 02:48:02 +08:00
zend_function_call_entry * fcall = zend_stack_top ( & CG ( function_call_stack ) ) ;
zend_function * function_ptr = fcall - > fbc ;
2013-08-29 02:12:54 +08:00
int send_by_reference = 0 ;
2005-06-22 16:33:00 +08:00
int send_function = 0 ;
2006-05-10 07:53:23 +08:00
2014-02-26 07:14:50 +08:00
fcall - > arg_num + + ;
1999-12-16 04:15:32 +08:00
Disallow use of positional args after unpacking
This commit disallows the use of trailing positional arguments
after argument unpacking was used. The following calls are no
longer valid:
fn(...$array, $var);
fn(...$array1, $var, ...$array2);
However, all of the following continue to be valid:
fn($var, ...$array);
fn(...$array1, ...$array2);
fn($var, ...$array1, ...$array2);
The reason behind this change is a stack allocation issue pointed
out by Dmitry: As of PHP 5.5 the stack necessary for pushing
arguments is precomputed and preallocated, as such the individual
SEND opcodes no longer verify that there is enough stack space.
The unpacked arguments will occupy some of that preallocated
space and as such following positional arguments could write past
a stack page boundary.
An alternative resolution for this issue is to ensure that there
is enough space for the remaining arguments in the UNPACK opcode.
However making this allocation precise (rather than using a
conversative over-estimate) would require some effort. Given that
this particular aspect of the feature wasn't very popular in the
first place, it doesn't seem worth the effort.
2014-02-26 23:08:58 +08:00
if ( fcall - > uses_argument_unpacking ) {
zend_error_noreturn ( E_COMPILE_ERROR ,
" Cannot use positional argument after argument unpacking " ) ;
}
1999-12-16 04:15:32 +08:00
2010-04-26 08:13:34 +08:00
if ( original_op = = ZEND_SEND_REF ) {
2008-06-16 02:27:37 +08:00
if ( function_ptr & &
function_ptr - > common . function_name & &
function_ptr - > common . type = = ZEND_USER_FUNCTION & &
2014-02-26 07:14:50 +08:00
! ARG_SHOULD_BE_SENT_BY_REF ( function_ptr , fcall - > arg_num ) ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR ,
2010-04-26 08:13:34 +08:00
" Call-time pass-by-reference has been removed; "
" If you would like to pass argument by reference, modify the declaration of %s(). " ,
2014-02-21 21:27:53 +08:00
function_ptr - > common . function_name - > val ) ;
2008-06-16 02:27:37 +08:00
} else {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Call-time pass-by-reference has been removed " ) ;
2008-06-16 02:27:37 +08:00
}
2010-04-26 08:13:34 +08:00
return ;
2013-01-28 10:02:51 +08:00
}
1999-06-07 01:35:42 +08:00
if ( function_ptr ) {
2014-02-26 07:14:50 +08:00
if ( ARG_MAY_BE_SENT_BY_REF ( function_ptr , fcall - > arg_num ) ) {
2013-08-29 02:12:54 +08:00
if ( op = = ZEND_SEND_VAR & & param - > op_type & ( IS_VAR | IS_CV ) ) {
send_by_reference = ZEND_ARG_SEND_BY_REF ;
if ( zend_is_function_or_method_call ( param ) ) {
2009-01-20 19:22:45 +08:00
/* Method call */
op = ZEND_SEND_VAR_NO_REF ;
2009-01-20 21:21:52 +08:00
send_function = ZEND_ARG_SEND_FUNCTION | ZEND_ARG_SEND_SILENT ;
2009-01-20 19:22:45 +08:00
}
} else {
op = ZEND_SEND_VAL ;
}
2014-02-26 07:14:50 +08:00
} else if ( ARG_SHOULD_BE_SENT_BY_REF ( function_ptr , fcall - > arg_num ) ) {
2013-08-29 02:12:54 +08:00
send_by_reference = ZEND_ARG_SEND_BY_REF ;
2005-08-10 20:02:52 +08:00
}
1999-06-07 01:35:42 +08:00
}
1999-04-08 02:10:10 +08:00
2001-12-26 22:46:18 +08:00
if ( op = = ZEND_SEND_VAR & & zend_is_function_or_method_call ( param ) ) {
2001-08-08 23:07:11 +08:00
/* Method call */
op = ZEND_SEND_VAR_NO_REF ;
2005-06-22 16:33:00 +08:00
send_function = ZEND_ARG_SEND_FUNCTION ;
2004-10-05 03:54:35 +08:00
} else if ( op = = ZEND_SEND_VAL & & ( param - > op_type & ( IS_VAR | IS_CV ) ) ) {
2001-08-08 23:07:11 +08:00
op = ZEND_SEND_VAR_NO_REF ;
1999-04-08 02:10:10 +08:00
}
2000-11-28 02:46:23 +08:00
2004-10-09 06:17:32 +08:00
if ( op ! = ZEND_SEND_VAR_NO_REF & & send_by_reference = = ZEND_ARG_SEND_BY_REF ) {
1999-04-08 02:10:10 +08:00
/* change to passing by reference */
switch ( param - > op_type ) {
case IS_VAR :
2004-10-05 03:54:35 +08:00
case IS_CV :
1999-04-08 02:10:10 +08:00
op = ZEND_SEND_REF ;
break ;
default :
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Only variables can be passed by reference " ) ;
1999-04-08 02:10:10 +08:00
break ;
}
}
2000-11-28 02:46:23 +08:00
if ( original_op = = ZEND_SEND_VAR ) {
2002-11-30 19:20:25 +08:00
switch ( op ) {
2000-10-30 03:16:29 +08:00
case ZEND_SEND_VAR_NO_REF :
2008-05-07 20:04:39 +08:00
zend_do_end_variable_parse ( param , BP_VAR_R , 0 TSRMLS_CC ) ;
2000-11-28 02:46:23 +08:00
break ;
1999-04-08 02:10:10 +08:00
case ZEND_SEND_VAR :
1999-06-07 01:35:42 +08:00
if ( function_ptr ) {
2008-05-07 20:04:39 +08:00
zend_do_end_variable_parse ( param , BP_VAR_R , 0 TSRMLS_CC ) ;
1999-06-07 01:35:42 +08:00
} else {
2014-02-26 07:14:50 +08:00
zend_do_end_variable_parse ( param , BP_VAR_FUNC_ARG , fcall - > arg_num TSRMLS_CC ) ;
1999-06-07 01:35:42 +08:00
}
1999-04-08 02:10:10 +08:00
break ;
case ZEND_SEND_REF :
2008-05-07 20:04:39 +08:00
zend_do_end_variable_parse ( param , BP_VAR_W , 0 TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
break ;
}
}
2001-07-28 18:51:54 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
2000-11-28 02:46:23 +08:00
if ( op = = ZEND_SEND_VAR_NO_REF ) {
if ( function_ptr ) {
2005-06-22 16:33:00 +08:00
opline - > extended_value = ZEND_ARG_COMPILE_TIME_BOUND | send_by_reference | send_function ;
2000-11-28 02:46:23 +08:00
} else {
2005-06-22 16:33:00 +08:00
opline - > extended_value = send_function ;
2000-11-28 02:46:23 +08:00
}
1999-09-22 04:00:01 +08:00
} else {
2000-11-28 02:46:23 +08:00
if ( function_ptr ) {
opline - > extended_value = ZEND_DO_FCALL ;
} else {
opline - > extended_value = ZEND_DO_FCALL_BY_NAME ;
}
1999-09-22 04:00:01 +08:00
}
1999-04-08 02:10:10 +08:00
opline - > opcode = op ;
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op1 , param ) ;
2014-02-26 07:14:50 +08:00
opline - > op2 . opline_num = fcall - > arg_num ;
1999-04-08 02:10:10 +08:00
SET_UNUSED ( opline - > op2 ) ;
2012-11-30 17:39:23 +08:00
if ( + + CG ( context ) . used_stack > CG ( active_op_array ) - > used_stack ) {
CG ( active_op_array ) - > used_stack = CG ( context ) . used_stack ;
}
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-02-26 07:14:50 +08:00
void zend_do_unpack_params ( znode * params TSRMLS_DC ) /* { { { */
2013-08-29 17:35:11 +08:00
{
zend_op * opline ;
2014-05-01 02:48:02 +08:00
zend_function_call_entry * fcall = zend_stack_top ( & CG ( function_call_stack ) ) ;
2013-08-29 17:35:11 +08:00
Disallow use of positional args after unpacking
This commit disallows the use of trailing positional arguments
after argument unpacking was used. The following calls are no
longer valid:
fn(...$array, $var);
fn(...$array1, $var, ...$array2);
However, all of the following continue to be valid:
fn($var, ...$array);
fn(...$array1, ...$array2);
fn($var, ...$array1, ...$array2);
The reason behind this change is a stack allocation issue pointed
out by Dmitry: As of PHP 5.5 the stack necessary for pushing
arguments is precomputed and preallocated, as such the individual
SEND opcodes no longer verify that there is enough stack space.
The unpacked arguments will occupy some of that preallocated
space and as such following positional arguments could write past
a stack page boundary.
An alternative resolution for this issue is to ensure that there
is enough space for the remaining arguments in the UNPACK opcode.
However making this allocation precise (rather than using a
conversative over-estimate) would require some effort. Given that
this particular aspect of the feature wasn't very popular in the
first place, it doesn't seem worth the effort.
2014-02-26 23:08:58 +08:00
fcall - > uses_argument_unpacking = 1 ;
2014-02-26 07:14:50 +08:00
2014-02-26 06:39:50 +08:00
if ( fcall - > fbc ) {
2013-08-29 17:35:11 +08:00
/* If argument unpacking is used argument numbers and sending modes can no longer be
* computed at compile time , thus we need access to EX ( call ) . In order to have it we
* retroactively emit a ZEND_INIT_FCALL_BY_NAME opcode . */
zval func_name ;
2014-04-26 04:32:51 +08:00
ZVAL_STR ( & func_name , STR_COPY ( fcall - > fbc - > common . function_name ) ) ;
2013-08-29 17:35:11 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
opline - > opcode = ZEND_INIT_FCALL_BY_NAME ;
opline - > result . num = CG ( context ) . nested_calls ;
SET_UNUSED ( opline - > op1 ) ;
opline - > op2_type = IS_CONST ;
opline - > op2 . constant = zend_add_func_name_literal ( CG ( active_op_array ) , & func_name TSRMLS_CC ) ;
GET_CACHE_SLOT ( opline - > op2 . constant ) ;
+ + CG ( context ) . nested_calls ;
2014-02-26 06:39:50 +08:00
fcall - > fbc = NULL ;
2013-08-29 17:35:11 +08:00
}
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
opline - > opcode = ZEND_SEND_UNPACK ;
SET_NODE ( opline - > op1 , params ) ;
SET_UNUSED ( opline - > op2 ) ;
2014-02-26 07:14:50 +08:00
opline - > op2 . num = fcall - > arg_num ;
2013-08-29 17:35:11 +08:00
}
/* }}} */
2014-04-22 22:52:59 +08:00
static int generate_free_switch_expr ( zend_switch_entry * switch_entry TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
1999-09-09 22:15:17 +08:00
zend_op * opline ;
2006-05-10 07:53:23 +08:00
2004-03-02 19:03:48 +08:00
if ( switch_entry - > cond . op_type ! = IS_VAR & & switch_entry - > cond . op_type ! = IS_TMP_VAR ) {
2005-04-25 17:56:42 +08:00
return ( switch_entry - > cond . op_type = = IS_UNUSED ) ;
1999-09-09 22:15:17 +08:00
}
2006-05-10 07:53:23 +08:00
2001-07-28 18:51:54 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
2008-05-05 19:03:35 +08:00
opline - > opcode = ( switch_entry - > cond . op_type = = IS_TMP_VAR ) ? ZEND_FREE : ZEND_SWITCH_FREE ;
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op1 , & switch_entry - > cond ) ;
1999-07-24 19:43:21 +08:00
SET_UNUSED ( opline - > op2 ) ;
2013-10-04 19:13:46 +08:00
1999-09-09 22:15:17 +08:00
return 0 ;
1999-07-24 19:43:21 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-07-24 19:43:21 +08:00
2009-07-27 22:11:53 +08:00
static int generate_free_foreach_copy ( const zend_op * foreach_copy TSRMLS_DC ) /* { { { */
1999-09-09 22:15:17 +08:00
{
zend_op * opline ;
2004-03-05 21:04:21 +08:00
2013-07-24 07:55:43 +08:00
/* If we reach the separator then stop applying the stack */
2013-10-04 19:13:46 +08:00
if ( foreach_copy - > result_type = = IS_UNUSED ) {
2004-03-05 21:04:21 +08:00
return 1 ;
2006-05-10 07:53:23 +08:00
}
1999-09-09 22:15:17 +08:00
2001-07-28 18:51:54 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-09-09 22:15:17 +08:00
2010-04-20 18:57:45 +08:00
opline - > opcode = ( foreach_copy - > result_type = = IS_TMP_VAR ) ? ZEND_FREE : ZEND_SWITCH_FREE ;
COPY_NODE ( opline - > op1 , foreach_copy - > result ) ;
1999-09-09 22:15:17 +08:00
SET_UNUSED ( opline - > op2 ) ;
2006-05-10 07:53:23 +08:00
1999-09-09 22:15:17 +08:00
return 0 ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-07-24 19:43:21 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_return ( znode * expr , int do_end_vparse TSRMLS_DC ) /* { { { */
1999-07-24 19:43:21 +08:00
{
zend_op * opline ;
2008-05-05 19:03:35 +08:00
int start_op_number , end_op_number ;
2012-07-23 02:11:09 +08:00
zend_bool returns_reference = ( CG ( active_op_array ) - > fn_flags & ZEND_ACC_RETURN_REFERENCE ) ! = 0 ;
2006-05-10 07:53:23 +08:00
2012-07-23 02:11:09 +08:00
/* The error for use of return inside a generator is thrown in pass_two. */
2006-05-10 07:53:23 +08:00
2001-07-19 23:53:38 +08:00
if ( do_end_vparse ) {
2012-07-17 19:24:27 +08:00
if ( returns_reference & & ! zend_is_function_or_method_call ( expr ) ) {
2014-02-26 22:07:16 +08:00
zend_do_end_variable_parse ( expr , BP_VAR_W , 1 TSRMLS_CC ) ;
2001-07-19 23:53:38 +08:00
} else {
2008-05-07 20:04:39 +08:00
zend_do_end_variable_parse ( expr , BP_VAR_R , 0 TSRMLS_CC ) ;
1999-12-16 04:15:32 +08:00
}
}
2001-07-19 23:53:38 +08:00
2008-05-05 19:03:35 +08:00
start_op_number = get_next_op_number ( CG ( active_op_array ) ) ;
1999-07-24 19:43:21 +08:00
# ifdef ZTS
2001-07-28 18:51:54 +08:00
zend_stack_apply_with_argument ( & CG ( switch_cond_stack ) , ZEND_STACK_APPLY_TOPDOWN , ( int ( * ) ( void * element , void * ) ) generate_free_switch_expr TSRMLS_CC ) ;
zend_stack_apply_with_argument ( & CG ( foreach_copy_stack ) , ZEND_STACK_APPLY_TOPDOWN , ( int ( * ) ( void * element , void * ) ) generate_free_foreach_copy TSRMLS_CC ) ;
1999-07-24 19:43:21 +08:00
# else
2000-03-30 06:28:04 +08:00
zend_stack_apply ( & CG ( switch_cond_stack ) , ZEND_STACK_APPLY_TOPDOWN , ( int ( * ) ( void * element ) ) generate_free_switch_expr ) ;
zend_stack_apply ( & CG ( foreach_copy_stack ) , ZEND_STACK_APPLY_TOPDOWN , ( int ( * ) ( void * element ) ) generate_free_foreach_copy ) ;
1999-07-24 19:43:21 +08:00
# endif
2008-05-05 19:03:35 +08:00
end_op_number = get_next_op_number ( CG ( active_op_array ) ) ;
while ( start_op_number < end_op_number ) {
2010-04-20 18:57:45 +08:00
CG ( active_op_array ) - > opcodes [ start_op_number ] . extended_value | = EXT_TYPE_FREE_ON_RETURN ;
2008-05-05 19:03:35 +08:00
start_op_number + + ;
}
2012-12-13 06:48:51 +08:00
if ( CG ( context ) . in_finally ) {
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
opline - > opcode = ZEND_DISCARD_EXCEPTION ;
SET_UNUSED ( opline - > op1 ) ;
SET_UNUSED ( opline - > op2 ) ;
}
2013-01-28 10:02:51 +08:00
2001-07-28 18:51:54 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-07-24 19:43:21 +08:00
2012-07-17 19:24:27 +08:00
opline - > opcode = returns_reference ? ZEND_RETURN_BY_REF : ZEND_RETURN ;
2006-05-10 07:53:23 +08:00
1999-04-08 02:10:10 +08:00
if ( expr ) {
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op1 , expr ) ;
2003-12-15 00:09:07 +08:00
2013-11-28 00:30:35 +08:00
if ( ! do_end_vparse ) {
opline - > extended_value = ZEND_RETURNS_VALUE ;
} else if ( zend_is_function_or_method_call ( expr ) ) {
2006-05-10 07:53:23 +08:00
opline - > extended_value = ZEND_RETURNS_FUNCTION ;
2003-12-15 00:09:07 +08:00
}
2007-02-01 23:23:46 +08:00
} else {
2010-04-20 18:57:45 +08:00
opline - > op1_type = IS_CONST ;
LITERAL_NULL ( opline - > op1 ) ;
2003-12-15 00:09:07 +08:00
}
1999-04-08 02:10:10 +08:00
SET_UNUSED ( opline - > op2 ) ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_yield ( znode * result , znode * value , znode * key , zend_bool is_variable TSRMLS_DC ) /* { { { */
2012-05-16 00:30:48 +08:00
{
2012-05-27 04:44:53 +08:00
zend_op * opline ;
2012-07-20 06:49:50 +08:00
if ( ! CG ( active_op_array ) - > function_name ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " The \" yield \" expression can only be used inside a function " ) ;
2012-05-20 00:49:27 +08:00
}
2012-07-20 06:49:50 +08:00
CG ( active_op_array ) - > fn_flags | = ZEND_ACC_GENERATOR ;
2012-07-22 03:05:46 +08:00
if ( is_variable ) {
if ( ( CG ( active_op_array ) - > fn_flags & ZEND_ACC_RETURN_REFERENCE ) & & ! zend_is_function_or_method_call ( value ) ) {
2014-02-26 22:07:16 +08:00
zend_do_end_variable_parse ( value , BP_VAR_W , 1 TSRMLS_CC ) ;
2012-07-22 03:05:46 +08:00
} else {
zend_do_end_variable_parse ( value , BP_VAR_R , 0 TSRMLS_CC ) ;
}
}
2012-05-27 04:44:53 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
opline - > opcode = ZEND_YIELD ;
2012-05-29 23:53:11 +08:00
2012-05-30 08:44:06 +08:00
if ( value ) {
SET_NODE ( opline - > op1 , value ) ;
2012-07-17 19:24:27 +08:00
2012-07-22 03:05:46 +08:00
if ( is_variable & & zend_is_function_or_method_call ( value ) ) {
2012-07-17 19:24:27 +08:00
opline - > extended_value = ZEND_RETURNS_FUNCTION ;
}
2012-05-30 08:44:06 +08:00
} else {
SET_UNUSED ( opline - > op1 ) ;
}
if ( key ) {
SET_NODE ( opline - > op2 , key ) ;
2012-05-29 23:53:11 +08:00
} else {
SET_UNUSED ( opline - > op2 ) ;
}
2012-05-29 23:34:33 +08:00
2013-11-30 20:05:40 +08:00
opline - > result_type = IS_VAR ;
2012-05-29 23:34:33 +08:00
opline - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
GET_NODE ( result , opline - > result ) ;
2012-05-16 00:30:48 +08:00
}
/* }}} */
2009-07-27 22:11:53 +08:00
static int zend_add_try_element ( zend_uint try_op TSRMLS_DC ) /* { { { */
2004-02-03 20:17:09 +08:00
{
int try_catch_offset = CG ( active_op_array ) - > last_try_catch + + ;
CG ( active_op_array ) - > try_catch_array = erealloc ( CG ( active_op_array ) - > try_catch_array , sizeof ( zend_try_catch_element ) * CG ( active_op_array ) - > last_try_catch ) ;
CG ( active_op_array ) - > try_catch_array [ try_catch_offset ] . try_op = try_op ;
2012-11-22 19:17:05 +08:00
CG ( active_op_array ) - > try_catch_array [ try_catch_offset ] . catch_op = 0 ;
2012-08-13 21:48:39 +08:00
CG ( active_op_array ) - > try_catch_array [ try_catch_offset ] . finally_op = 0 ;
2012-08-18 00:16:34 +08:00
CG ( active_op_array ) - > try_catch_array [ try_catch_offset ] . finally_end = 0 ;
2004-02-03 20:17:09 +08:00
return try_catch_offset ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
2004-02-03 20:17:09 +08:00
2009-07-27 22:11:53 +08:00
static void zend_add_catch_element ( int offset , zend_uint catch_op TSRMLS_DC ) /* { { { */
2004-02-03 20:17:09 +08:00
{
CG ( active_op_array ) - > try_catch_array [ offset ] . catch_op = catch_op ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
2004-02-03 20:17:09 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_first_catch ( znode * open_parentheses TSRMLS_DC ) /* { { { */
2004-02-03 20:17:09 +08:00
{
2010-04-20 18:57:45 +08:00
open_parentheses - > u . op . opline_num = get_next_op_number ( CG ( active_op_array ) ) ;
2004-02-03 20:17:09 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2004-02-03 20:17:09 +08:00
2012-08-13 21:48:39 +08:00
void zend_initialize_try_catch_element ( znode * catch_token TSRMLS_DC ) /* { { { */
2004-02-03 20:17:09 +08:00
{
2007-01-09 23:06:07 +08:00
int jmp_op_number = get_next_op_number ( CG ( active_op_array ) ) ;
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
zend_llist jmp_list ;
zend_llist * jmp_list_ptr ;
opline - > opcode = ZEND_JMP ;
SET_UNUSED ( opline - > op1 ) ;
SET_UNUSED ( opline - > op2 ) ;
/* save for backpatching */
zend_llist_init ( & jmp_list , sizeof ( int ) , NULL , 0 ) ;
2014-05-01 02:28:02 +08:00
zend_stack_push ( & CG ( bp_stack ) , ( void * ) & jmp_list ) ;
2014-05-01 02:48:02 +08:00
jmp_list_ptr = zend_stack_top ( & CG ( bp_stack ) ) ;
2007-01-09 23:06:07 +08:00
zend_llist_add_element ( jmp_list_ptr , & jmp_op_number ) ;
2012-08-22 18:32:03 +08:00
catch_token - > EA = get_next_op_number ( CG ( active_op_array ) ) ;
2004-02-03 20:17:09 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2004-02-03 20:17:09 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_mark_last_catch ( const znode * first_catch , const znode * last_additional_catch TSRMLS_DC ) /* { { { */
2004-02-03 20:17:09 +08:00
{
2007-01-09 23:06:07 +08:00
CG ( active_op_array ) - > last - - ;
zend_do_if_end ( TSRMLS_C ) ;
2010-04-20 18:57:45 +08:00
if ( last_additional_catch - > u . op . opline_num = = - 1 ) {
CG ( active_op_array ) - > opcodes [ first_catch - > u . op . opline_num ] . result . num = 1 ;
CG ( active_op_array ) - > opcodes [ first_catch - > u . op . opline_num ] . extended_value = get_next_op_number ( CG ( active_op_array ) ) ;
2004-02-03 20:17:09 +08:00
} else {
2010-04-20 18:57:45 +08:00
CG ( active_op_array ) - > opcodes [ last_additional_catch - > u . op . opline_num ] . result . num = 1 ;
CG ( active_op_array ) - > opcodes [ last_additional_catch - > u . op . opline_num ] . extended_value = get_next_op_number ( CG ( active_op_array ) ) ;
2004-02-03 20:17:09 +08:00
}
2005-11-24 19:33:11 +08:00
DEC_BPC ( CG ( active_op_array ) ) ;
2004-02-03 20:17:09 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2004-02-03 20:17:09 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_try ( znode * try_token TSRMLS_DC ) /* { { { */
2001-08-30 23:26:30 +08:00
{
2010-04-20 18:57:45 +08:00
try_token - > u . op . opline_num = zend_add_try_element ( get_next_op_number ( CG ( active_op_array ) ) TSRMLS_CC ) ;
2005-11-24 19:33:11 +08:00
INC_BPC ( CG ( active_op_array ) ) ;
2001-08-30 23:26:30 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2001-08-30 23:26:30 +08:00
2012-11-22 19:17:05 +08:00
void zend_do_finally ( znode * finally_token TSRMLS_DC ) /* { { { */
{
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
2012-08-14 08:59:40 +08:00
finally_token - > u . op . opline_num = get_next_op_number ( CG ( active_op_array ) ) ;
2012-11-22 19:17:05 +08:00
/* call the the "finally" block */
opline - > opcode = ZEND_FAST_CALL ;
SET_UNUSED ( opline - > op1 ) ;
opline - > op1 . opline_num = finally_token - > u . op . opline_num + 1 ;
SET_UNUSED ( opline - > op2 ) ;
/* jump to code after the "finally" block,
* the actual jump address is going to be set in zend_do_end_finally ( )
*/
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
opline - > opcode = ZEND_JMP ;
SET_UNUSED ( opline - > op1 ) ;
SET_UNUSED ( opline - > op2 ) ;
2012-12-13 06:48:51 +08:00
CG ( context ) . in_finally + + ;
2012-11-22 19:17:05 +08:00
}
/* }}} */
2012-08-13 21:48:39 +08:00
void zend_do_begin_catch ( znode * catch_token , znode * class_name , znode * catch_var , znode * first_catch TSRMLS_DC ) /* { { { */
2001-08-30 23:26:30 +08:00
{
2007-09-29 03:52:53 +08:00
long catch_op_number ;
2001-08-30 23:26:30 +08:00
zend_op * opline ;
2007-09-29 03:52:53 +08:00
znode catch_class ;
2006-05-10 07:53:23 +08:00
2010-04-20 19:16:39 +08:00
if ( class_name - > op_type = = IS_CONST & &
ZEND_FETCH_CLASS_DEFAULT = = zend_get_class_fetch_type ( Z_STRVAL ( class_name - > u . constant ) , Z_STRLEN ( class_name - > u . constant ) ) ) {
2013-09-13 18:18:39 +08:00
zend_resolve_class_name ( class_name TSRMLS_CC ) ;
2010-04-20 19:16:39 +08:00
catch_class = * class_name ;
} else {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Bad class name in the catch statement " ) ;
2005-09-09 14:48:49 +08:00
}
2010-04-20 19:16:39 +08:00
catch_op_number = get_next_op_number ( CG ( active_op_array ) ) ;
2007-09-29 03:52:53 +08:00
if ( first_catch ) {
2010-04-20 18:57:45 +08:00
first_catch - > u . op . opline_num = catch_op_number ;
2007-09-29 03:52:53 +08:00
}
2001-08-31 01:27:43 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
2001-08-30 23:26:30 +08:00
opline - > opcode = ZEND_CATCH ;
2010-04-21 22:58:33 +08:00
opline - > op1_type = IS_CONST ;
2010-04-21 23:08:10 +08:00
opline - > op1 . constant = zend_add_class_name_literal ( CG ( active_op_array ) , & catch_class . u . constant TSRMLS_CC ) ;
2010-04-20 18:57:45 +08:00
opline - > op2_type = IS_CV ;
2014-02-10 14:04:30 +08:00
opline - > op2 . var = lookup_cv ( CG ( active_op_array ) , Z_STR ( catch_var - > u . constant ) TSRMLS_CC ) ;
2014-03-27 20:00:25 +08:00
Z_STR ( catch_var - > u . constant ) = CG ( active_op_array ) - > vars [ EX_VAR_TO_NUM ( opline - > op2 . var ) ] ;
2010-04-20 18:57:45 +08:00
opline - > result . num = 0 ; /* 1 means it's the last catch in the block */
2001-08-30 23:26:30 +08:00
2012-08-13 21:48:39 +08:00
catch_token - > u . op . opline_num = catch_op_number ;
2001-08-30 23:26:30 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2001-08-30 23:26:30 +08:00
2012-08-13 21:48:39 +08:00
void zend_do_end_catch ( znode * catch_token TSRMLS_DC ) /* { { { */
2001-08-30 23:26:30 +08:00
{
2007-01-09 23:06:07 +08:00
int jmp_op_number = get_next_op_number ( CG ( active_op_array ) ) ;
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
zend_llist * jmp_list_ptr ;
opline - > opcode = ZEND_JMP ;
SET_UNUSED ( opline - > op1 ) ;
SET_UNUSED ( opline - > op2 ) ;
/* save for backpatching */
2014-05-01 02:48:02 +08:00
jmp_list_ptr = zend_stack_top ( & CG ( bp_stack ) ) ;
2007-01-09 23:06:07 +08:00
zend_llist_add_element ( jmp_list_ptr , & jmp_op_number ) ;
2012-08-13 21:48:39 +08:00
CG ( active_op_array ) - > opcodes [ catch_token - > u . op . opline_num ] . extended_value = get_next_op_number ( CG ( active_op_array ) ) ;
}
/* }}} */
void zend_do_bind_catch ( znode * try_token , znode * catch_token TSRMLS_DC ) /* { { { */ {
2012-08-14 08:59:40 +08:00
if ( catch_token - > op_type ! = IS_UNUSED ) {
zend_add_catch_element ( try_token - > u . op . opline_num , catch_token - > EA TSRMLS_CC ) ;
}
2012-08-13 21:48:39 +08:00
}
/* }}} */
void zend_do_end_finally ( znode * try_token , znode * catch_token , znode * finally_token TSRMLS_DC ) /* { { { */
{
2012-08-14 08:59:40 +08:00
if ( catch_token - > op_type = = IS_UNUSED & & finally_token - > op_type = = IS_UNUSED ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use try without catch or finally " ) ;
2013-01-28 10:02:51 +08:00
}
2012-08-14 08:59:40 +08:00
if ( finally_token - > op_type ! = IS_UNUSED ) {
2012-11-22 19:17:05 +08:00
zend_op * opline ;
2013-01-28 10:02:51 +08:00
2012-11-22 19:17:05 +08:00
CG ( active_op_array ) - > try_catch_array [ try_token - > u . op . opline_num ] . finally_op = finally_token - > u . op . opline_num + 1 ;
2012-08-18 00:16:34 +08:00
CG ( active_op_array ) - > try_catch_array [ try_token - > u . op . opline_num ] . finally_end = get_next_op_number ( CG ( active_op_array ) ) ;
2012-08-22 18:32:03 +08:00
CG ( active_op_array ) - > has_finally_block = 1 ;
2012-08-13 21:48:39 +08:00
2012-11-22 19:17:05 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
opline - > opcode = ZEND_FAST_RET ;
2012-08-14 08:59:40 +08:00
SET_UNUSED ( opline - > op1 ) ;
SET_UNUSED ( opline - > op2 ) ;
2013-01-28 10:02:51 +08:00
2012-11-22 19:17:05 +08:00
CG ( active_op_array ) - > opcodes [ finally_token - > u . op . opline_num ] . op1 . opline_num = get_next_op_number ( CG ( active_op_array ) ) ;
2012-12-13 06:48:51 +08:00
CG ( context ) . in_finally - - ;
2013-01-28 10:02:51 +08:00
}
2001-08-30 23:26:30 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2001-08-30 23:26:30 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_throw ( znode * expr TSRMLS_DC ) /* { { { */
2001-08-30 23:26:30 +08:00
{
zend_op * opline ;
2006-05-10 07:53:23 +08:00
2001-08-31 01:27:43 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
2001-08-30 23:26:30 +08:00
opline - > opcode = ZEND_THROW ;
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op1 , expr ) ;
2001-08-30 23:26:30 +08:00
SET_UNUSED ( opline - > op2 ) ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
2001-08-30 23:26:30 +08:00
2009-07-27 22:11:53 +08:00
ZEND_API void function_add_ref ( zend_function * function ) /* { { { */
1999-07-09 00:55:27 +08:00
{
if ( function - > type = = ZEND_USER_FUNCTION ) {
1999-12-24 03:23:36 +08:00
zend_op_array * op_array = & function - > op_array ;
( * op_array - > refcount ) + + ;
if ( op_array - > static_variables ) {
HashTable * static_variables = op_array - > static_variables ;
1999-12-28 03:07:33 +08:00
ALLOC_HASHTABLE ( op_array - > static_variables ) ;
2014-05-24 00:37:53 +08:00
zend_array_dup ( op_array - > static_variables , static_variables ) ;
1999-12-24 03:23:36 +08:00
}
2010-05-24 22:11:39 +08:00
op_array - > run_time_cache = NULL ;
2014-04-10 03:40:01 +08:00
} else if ( function - > type = = ZEND_INTERNAL_FUNCTION ) {
if ( function - > common . function_name ) {
STR_ADDREF ( function - > common . function_name ) ;
}
1999-07-09 00:55:27 +08:00
}
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-07-09 00:55:27 +08:00
2009-07-27 22:11:53 +08:00
static void do_inherit_parent_constructor ( zend_class_entry * ce ) /* { { { */
1999-07-28 04:34:31 +08:00
{
2011-12-05 17:20:12 +08:00
zend_function * function , * new_function ;
2003-09-04 05:21:18 +08:00
2003-05-08 23:04:43 +08:00
if ( ! ce - > parent ) {
return ;
}
2003-09-04 04:26:01 +08:00
/* You cannot change create_object */
ce - > create_object = ce - > parent - > create_object ;
2005-02-23 19:15:51 +08:00
2003-09-04 04:26:01 +08:00
/* Inherit special functions if needed */
2003-10-19 02:43:31 +08:00
if ( ! ce - > get_iterator ) {
ce - > get_iterator = ce - > parent - > get_iterator ;
}
if ( ! ce - > iterator_funcs . funcs ) {
ce - > iterator_funcs . funcs = ce - > parent - > iterator_funcs . funcs ;
}
2003-08-17 20:16:10 +08:00
if ( ! ce - > __get ) {
ce - > __get = ce - > parent - > __get ;
}
if ( ! ce - > __set ) {
ce - > __set = ce - > parent - > __set ;
}
2005-07-08 00:07:09 +08:00
if ( ! ce - > __unset ) {
ce - > __unset = ce - > parent - > __unset ;
}
if ( ! ce - > __isset ) {
ce - > __isset = ce - > parent - > __isset ;
}
2003-08-17 20:16:10 +08:00
if ( ! ce - > __call ) {
ce - > __call = ce - > parent - > __call ;
}
2007-09-29 16:52:40 +08:00
if ( ! ce - > __callstatic ) {
ce - > __callstatic = ce - > parent - > __callstatic ;
}
2006-05-10 07:53:23 +08:00
if ( ! ce - > __tostring ) {
ce - > __tostring = ce - > parent - > __tostring ;
}
2003-09-04 04:26:01 +08:00
if ( ! ce - > clone ) {
ce - > clone = ce - > parent - > clone ;
}
2005-02-23 19:15:51 +08:00
if ( ! ce - > serialize ) {
ce - > serialize = ce - > parent - > serialize ;
}
if ( ! ce - > unserialize ) {
ce - > unserialize = ce - > parent - > unserialize ;
}
2003-08-17 20:16:10 +08:00
if ( ! ce - > destructor ) {
ce - > destructor = ce - > parent - > destructor ;
}
2014-02-20 09:07:34 +08:00
if ( ! ce - > __debugInfo ) {
ce - > __debugInfo = ce - > parent - > __debugInfo ;
}
2003-09-04 05:21:18 +08:00
if ( ce - > constructor ) {
2005-12-17 23:51:52 +08:00
if ( ce - > parent - > constructor & & ce - > parent - > constructor - > common . fn_flags & ZEND_ACC_FINAL ) {
zend_error ( E_ERROR , " Cannot override final %s::%s() with %s::%s() " ,
2014-02-10 14:04:30 +08:00
ce - > parent - > name - > val , ce - > parent - > constructor - > common . function_name - > val ,
ce - > name - > val , ce - > constructor - > common . function_name - > val
2005-12-17 23:51:52 +08:00
) ;
}
2003-09-04 05:21:18 +08:00
return ;
2002-06-23 23:46:58 +08:00
}
2006-05-10 07:53:23 +08:00
2014-02-10 14:04:30 +08:00
if ( ( function = zend_hash_str_find_ptr ( & ce - > parent - > function_table , ZEND_CONSTRUCTOR_FUNC_NAME , sizeof ( ZEND_CONSTRUCTOR_FUNC_NAME ) - 1 ) ) ! = NULL ) {
2003-09-04 05:21:18 +08:00
/* inherit parent's constructor */
2014-02-17 21:59:18 +08:00
if ( function - > type = = ZEND_INTERNAL_FUNCTION ) {
new_function = pemalloc ( sizeof ( zend_internal_function ) , 1 ) ;
memcpy ( new_function , function , sizeof ( zend_internal_function ) ) ;
} else {
new_function = emalloc ( sizeof ( zend_op_array ) ) ;
memcpy ( new_function , function , sizeof ( zend_op_array ) ) ;
}
zend_hash_str_update_ptr ( & ce - > function_table , ZEND_CONSTRUCTOR_FUNC_NAME , sizeof ( ZEND_CONSTRUCTOR_FUNC_NAME ) - 1 , new_function ) ;
2011-12-05 17:20:12 +08:00
function_add_ref ( new_function ) ;
2003-09-04 05:21:18 +08:00
} else {
2004-03-16 23:22:44 +08:00
/* Don't inherit the old style constructor if we already have the new style constructor */
2014-02-10 14:04:30 +08:00
zend_string * lc_class_name ;
zend_string * lc_parent_class_name ;
lc_class_name = STR_ALLOC ( ce - > name - > len , 0 ) ;
zend_str_tolower_copy ( lc_class_name - > val , ce - > name - > val , ce - > name - > len ) ;
if ( ! zend_hash_exists ( & ce - > function_table , lc_class_name ) ) {
lc_parent_class_name = STR_ALLOC ( ce - > parent - > name - > len , 0 ) ;
zend_str_tolower_copy ( lc_parent_class_name - > val , ce - > parent - > name - > val , ce - > parent - > name - > len ) ;
if ( ! zend_hash_exists ( & ce - > function_table , lc_parent_class_name ) & &
( function = zend_hash_find_ptr ( & ce - > parent - > function_table , lc_parent_class_name ) ) ! = NULL ) {
2004-08-27 06:25:55 +08:00
if ( function - > common . fn_flags & ZEND_ACC_CTOR ) {
/* inherit parent's constructor */
2014-02-17 21:59:18 +08:00
new_function = pemalloc ( sizeof ( zend_function ) , function - > type = = ZEND_INTERNAL_FUNCTION ) ;
memcpy ( new_function , function , sizeof ( zend_function ) ) ;
zend_hash_update_ptr ( & ce - > function_table , lc_parent_class_name , new_function ) ;
2011-12-05 17:20:12 +08:00
function_add_ref ( new_function ) ;
2004-08-27 06:25:55 +08:00
}
2003-09-04 05:21:18 +08:00
}
2014-02-10 14:04:30 +08:00
STR_RELEASE ( lc_parent_class_name ) ;
2003-09-04 05:21:18 +08:00
}
2014-02-10 14:04:30 +08:00
STR_FREE ( lc_class_name ) ;
2003-09-04 05:21:18 +08:00
}
ce - > constructor = ce - > parent - > constructor ;
1999-07-28 04:34:31 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-07-28 04:34:31 +08:00
2009-07-27 22:11:53 +08:00
char * zend_visibility_string ( zend_uint fn_flags ) /* { { { */
2002-12-07 01:09:44 +08:00
{
if ( fn_flags & ZEND_ACC_PRIVATE ) {
return " private " ;
}
if ( fn_flags & ZEND_ACC_PROTECTED ) {
return " protected " ;
}
if ( fn_flags & ZEND_ACC_PUBLIC ) {
return " public " ;
}
return " " ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
2002-12-07 01:09:44 +08:00
2014-05-27 01:29:35 +08:00
static zend_function * do_inherit_method ( zend_function * old_function ) /* { { { */
2002-12-07 01:09:44 +08:00
{
2014-02-17 21:59:18 +08:00
zend_function * new_function ;
if ( old_function - > type = = ZEND_INTERNAL_FUNCTION ) {
new_function = pemalloc ( sizeof ( zend_internal_function ) , 1 ) ;
memcpy ( new_function , old_function , sizeof ( zend_internal_function ) ) ;
} else {
new_function = emalloc ( sizeof ( zend_op_array ) ) ;
memcpy ( new_function , old_function , sizeof ( zend_op_array ) ) ;
}
2002-12-07 01:09:44 +08:00
/* The class entry of the derived function intentionally remains the same
* as that of the parent class . That allows us to know in which context
* we ' re running , and handle private method calls properly .
*/
2014-02-17 21:59:18 +08:00
function_add_ref ( new_function ) ;
2014-05-27 01:29:35 +08:00
return new_function ;
2002-12-07 01:09:44 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2002-12-07 01:09:44 +08:00
2011-06-14 01:52:23 +08:00
static zend_bool zend_do_perform_implementation_check ( const zend_function * fe , const zend_function * proto TSRMLS_DC ) /* { { { */
2003-03-29 19:19:38 +08:00
{
2013-09-27 00:39:17 +08:00
zend_uint i , num_args ;
2003-03-29 19:19:38 +08:00
2010-06-27 06:05:13 +08:00
/* If it's a user function then arg_info == NULL means we don't have any parameters but
* we still need to do the arg number checks . We are only willing to ignore this for internal
* functions because extensions don ' t always define arg_info .
*/
2004-03-01 02:25:50 +08:00
if ( ! proto | | ( ! proto - > common . arg_info & & proto - > common . type ! = ZEND_USER_FUNCTION ) ) {
2003-03-29 19:19:38 +08:00
return 1 ;
}
2010-06-27 06:05:13 +08:00
/* Checks for constructors only if they are declared in an interface,
* or explicitly marked as abstract
*/
if ( ( fe - > common . fn_flags & ZEND_ACC_CTOR )
& & ( ( proto - > common . scope - > ce_flags & ZEND_ACC_INTERFACE ) = = 0
& & ( proto - > common . fn_flags & ZEND_ACC_ABSTRACT ) = = 0 ) ) {
2004-04-21 16:44:37 +08:00
return 1 ;
}
2012-08-28 20:06:18 +08:00
/* If both methods are private do not enforce a signature */
if ( ( fe - > common . fn_flags & ZEND_ACC_PRIVATE ) & & ( proto - > common . fn_flags & ZEND_ACC_PRIVATE ) ) {
return 1 ;
}
2004-02-25 17:25:37 +08:00
/* check number of arguments */
2008-03-01 21:53:32 +08:00
if ( proto - > common . required_num_args < fe - > common . required_num_args
2004-02-25 17:25:37 +08:00
| | proto - > common . num_args > fe - > common . num_args ) {
return 0 ;
}
2010-11-03 23:40:24 +08:00
/* by-ref constraints on return values are covariant */
if ( ( proto - > common . fn_flags & ZEND_ACC_RETURN_REFERENCE )
& & ! ( fe - > common . fn_flags & ZEND_ACC_RETURN_REFERENCE ) ) {
2005-06-16 22:56:13 +08:00
return 0 ;
2004-02-12 21:49:55 +08:00
}
2013-09-27 00:39:17 +08:00
if ( ( proto - > common . fn_flags & ZEND_ACC_VARIADIC )
& & ! ( fe - > common . fn_flags & ZEND_ACC_VARIADIC ) ) {
return 0 ;
}
/* For variadic functions any additional (optional) arguments that were added must be
* checked against the signature of the variadic argument , so in this case we have to
* go through all the parameters of the function and not just those present in the
* prototype . */
num_args = proto - > common . num_args ;
if ( ( fe - > common . fn_flags & ZEND_ACC_VARIADIC )
& & fe - > common . num_args > proto - > common . num_args ) {
num_args = fe - > common . num_args ;
}
for ( i = 0 ; i < num_args ; i + + ) {
zend_arg_info * fe_arg_info = & fe - > common . arg_info [ i ] ;
zend_arg_info * proto_arg_info ;
if ( i < proto - > common . num_args ) {
proto_arg_info = & proto - > common . arg_info [ i ] ;
} else {
proto_arg_info = & proto - > common . arg_info [ proto - > common . num_args - 1 ] ;
}
if ( ZEND_LOG_XOR ( fe_arg_info - > class_name , proto_arg_info - > class_name ) ) {
2003-08-04 15:53:09 +08:00
/* Only one has a type hint and the other one doesn't */
return 0 ;
}
2007-11-09 21:34:39 +08:00
2013-09-27 00:39:17 +08:00
if ( fe_arg_info - > class_name ) {
2014-02-10 14:04:30 +08:00
zend_string * fe_class_name , * proto_class_name ;
2012-03-02 11:32:12 +08:00
2014-02-21 23:02:24 +08:00
if ( ! strcasecmp ( fe_arg_info - > class_name , " parent " ) & & proto - > common . scope ) {
2014-02-24 17:33:30 +08:00
fe_class_name = STR_COPY ( proto - > common . scope - > name ) ;
2014-02-21 23:02:24 +08:00
} else if ( ! strcasecmp ( fe_arg_info - > class_name , " self " ) & & fe - > common . scope ) {
2014-02-24 17:33:30 +08:00
fe_class_name = STR_COPY ( fe - > common . scope - > name ) ;
2012-03-02 11:32:12 +08:00
} else {
2014-02-21 23:02:24 +08:00
fe_class_name = STR_INIT (
fe_arg_info - > class_name ,
fe_arg_info - > class_name_len , 0 ) ;
2012-03-02 11:32:12 +08:00
}
2014-02-21 23:02:24 +08:00
if ( ! strcasecmp ( proto_arg_info - > class_name , " parent " ) & & proto - > common . scope & & proto - > common . scope - > parent ) {
2014-02-24 17:33:30 +08:00
proto_class_name = STR_COPY ( proto - > common . scope - > parent - > name ) ;
2014-02-21 23:02:24 +08:00
} else if ( ! strcasecmp ( proto_arg_info - > class_name , " self " ) & & proto - > common . scope ) {
2014-02-24 17:33:30 +08:00
proto_class_name = STR_COPY ( proto - > common . scope - > name ) ;
2012-03-02 11:32:12 +08:00
} else {
2014-02-21 23:02:24 +08:00
proto_class_name = STR_INIT (
proto_arg_info - > class_name ,
proto_arg_info - > class_name_len , 0 ) ;
2012-03-02 11:32:12 +08:00
}
2014-02-10 14:04:30 +08:00
if ( strcasecmp ( fe_class_name - > val , proto_class_name - > val ) ! = 0 ) {
2012-03-02 11:32:12 +08:00
const char * colon ;
if ( fe - > common . type ! = ZEND_USER_FUNCTION ) {
2014-02-24 17:33:30 +08:00
STR_RELEASE ( proto_class_name ) ;
STR_RELEASE ( fe_class_name ) ;
2011-06-13 05:10:31 +08:00
return 0 ;
2014-02-10 14:04:30 +08:00
} else if ( strchr ( proto_class_name - > val , ' \\ ' ) ! = NULL | |
( colon = zend_memrchr ( fe_class_name - > val , ' \\ ' , fe_class_name - > len ) ) = = NULL | |
strcasecmp ( colon + 1 , proto_class_name - > val ) ! = 0 ) {
zend_class_entry * fe_ce , * proto_ce ;
2012-03-02 11:32:12 +08:00
2014-02-10 14:04:30 +08:00
fe_ce = zend_lookup_class ( fe_class_name TSRMLS_CC ) ;
proto_ce = zend_lookup_class ( proto_class_name TSRMLS_CC ) ;
2012-03-02 11:32:12 +08:00
/* Check for class alias */
2014-02-10 14:04:30 +08:00
if ( ! fe_ce | | ! proto_ce | |
fe_ce - > type = = ZEND_INTERNAL_CLASS | |
proto_ce - > type = = ZEND_INTERNAL_CLASS | |
fe_ce ! = proto_ce ) {
2014-02-24 17:33:30 +08:00
STR_RELEASE ( proto_class_name ) ;
STR_RELEASE ( fe_class_name ) ;
2012-03-02 11:32:12 +08:00
return 0 ;
}
2011-06-13 05:10:31 +08:00
}
2013-01-28 10:02:51 +08:00
}
2014-02-24 17:33:30 +08:00
STR_RELEASE ( proto_class_name ) ;
STR_RELEASE ( fe_class_name ) ;
2013-01-28 10:02:51 +08:00
}
2013-09-27 00:39:17 +08:00
if ( fe_arg_info - > type_hint ! = proto_arg_info - > type_hint ) {
2010-05-21 03:18:35 +08:00
/* Incompatible type hint */
2005-05-26 21:46:17 +08:00
return 0 ;
}
2010-11-03 23:40:24 +08:00
/* by-ref constraints on arguments are invariant */
2013-09-27 00:39:17 +08:00
if ( fe_arg_info - > pass_by_reference ! = proto_arg_info - > pass_by_reference ) {
2003-03-29 19:19:38 +08:00
return 0 ;
}
2003-07-16 17:13:47 +08:00
}
2004-02-25 17:25:37 +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
return 1 ;
2003-03-29 19:19:38 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2003-03-29 19:19:38 +08:00
2011-09-23 23:08:11 +08:00
# define REALLOC_BUF_IF_EXCEED(buf, offset, length, size) \
if ( UNEXPECTED ( offset - buf + size > = length ) ) { \
length + = size + 1 ; \
buf = erealloc ( buf , length ) ; \
}
2013-01-28 10:02:51 +08:00
static char * zend_get_function_declaration ( zend_function * fptr TSRMLS_DC ) /* { { { */
2011-09-23 23:08:11 +08:00
{
char * offset , * buf ;
zend_uint length = 1024 ;
offset = buf = ( char * ) emalloc ( length * sizeof ( char ) ) ;
if ( fptr - > op_array . fn_flags & ZEND_ACC_RETURN_REFERENCE ) {
* ( offset + + ) = ' & ' ;
* ( offset + + ) = ' ' ;
}
if ( fptr - > common . scope ) {
2014-02-10 14:04:30 +08:00
memcpy ( offset , fptr - > common . scope - > name - > val , fptr - > common . scope - > name - > len ) ;
offset + = fptr - > common . scope - > name - > len ;
2011-09-23 23:08:11 +08:00
* ( offset + + ) = ' : ' ;
* ( offset + + ) = ' : ' ;
}
2013-01-28 10:02:51 +08:00
2011-09-23 23:08:11 +08:00
{
2014-02-10 14:04:30 +08:00
size_t name_len = fptr - > common . function_name - > len ;
2011-09-23 23:08:11 +08:00
REALLOC_BUF_IF_EXCEED ( buf , offset , length , name_len ) ;
2014-02-10 14:04:30 +08:00
memcpy ( offset , fptr - > common . function_name - > val , name_len ) ;
2011-09-23 23:08:11 +08:00
offset + = name_len ;
}
* ( offset + + ) = ' ( ' ;
if ( fptr - > common . arg_info ) {
zend_uint i , required ;
zend_arg_info * arg_info = fptr - > common . arg_info ;
required = fptr - > common . required_num_args ;
for ( i = 0 ; i < fptr - > common . num_args ; ) {
if ( arg_info - > class_name ) {
2014-02-21 23:02:24 +08:00
const char * class_name ;
zend_uint class_name_len ;
if ( ! strcasecmp ( arg_info - > class_name , " self " ) & & fptr - > common . scope ) {
class_name = fptr - > common . scope - > name - > val ;
class_name_len = fptr - > common . scope - > name - > len ;
} else if ( ! strcasecmp ( arg_info - > class_name , " parent " ) & & fptr - > common . scope - > parent ) {
class_name = fptr - > common . scope - > parent - > name - > val ;
class_name_len = fptr - > common . scope - > parent - > name - > len ;
2012-03-02 11:32:12 +08:00
} else {
class_name = arg_info - > class_name ;
2014-02-21 23:02:24 +08:00
class_name_len = arg_info - > class_name_len ;
2012-03-02 11:32:12 +08:00
}
2014-02-21 23:02:24 +08:00
REALLOC_BUF_IF_EXCEED ( buf , offset , length , class_name_len ) ;
memcpy ( offset , class_name , class_name_len ) ;
offset + = class_name_len ;
2011-09-23 23:08:11 +08:00
* ( offset + + ) = ' ' ;
} else if ( arg_info - > type_hint ) {
zend_uint type_name_len ;
char * type_name = zend_get_type_by_const ( arg_info - > type_hint ) ;
type_name_len = strlen ( type_name ) ;
REALLOC_BUF_IF_EXCEED ( buf , offset , length , type_name_len ) ;
memcpy ( offset , type_name , type_name_len ) ;
offset + = type_name_len ;
* ( offset + + ) = ' ' ;
}
2013-01-28 10:02:51 +08:00
2011-09-23 23:08:11 +08:00
if ( arg_info - > pass_by_reference ) {
* ( offset + + ) = ' & ' ;
}
2013-09-27 00:39:17 +08:00
if ( arg_info - > is_variadic ) {
* ( offset + + ) = ' . ' ;
* ( offset + + ) = ' . ' ;
* ( offset + + ) = ' . ' ;
}
2011-09-23 23:08:11 +08:00
* ( offset + + ) = ' $ ' ;
if ( arg_info - > name ) {
REALLOC_BUF_IF_EXCEED ( buf , offset , length , arg_info - > name_len ) ;
memcpy ( offset , arg_info - > name , arg_info - > name_len ) ;
offset + = arg_info - > name_len ;
} else {
zend_uint idx = i ;
memcpy ( offset , " param " , 5 ) ;
offset + = 5 ;
do {
* ( offset + + ) = ( char ) ( idx % 10 ) + ' 0 ' ;
idx / = 10 ;
} while ( idx > 0 ) ;
}
2013-09-27 00:39:17 +08:00
if ( i > = required & & ! arg_info - > is_variadic ) {
2011-09-23 23:08:11 +08:00
* ( offset + + ) = ' ' ;
* ( offset + + ) = ' = ' ;
* ( offset + + ) = ' ' ;
if ( fptr - > type = = ZEND_USER_FUNCTION ) {
zend_op * precv = NULL ;
{
zend_uint idx = i ;
zend_op * op = ( ( zend_op_array * ) fptr ) - > opcodes ;
zend_op * end = op + ( ( zend_op_array * ) fptr ) - > last ;
+ + idx ;
while ( op < end ) {
if ( ( op - > opcode = = ZEND_RECV | | op - > opcode = = ZEND_RECV_INIT )
& & op - > op1 . num = = ( long ) idx )
{
precv = op ;
}
+ + op ;
}
}
if ( precv & & precv - > opcode = = ZEND_RECV_INIT & & precv - > op2_type ! = IS_UNUSED ) {
2014-04-21 23:51:15 +08:00
zval zv ;
2014-02-10 14:04:30 +08:00
ZVAL_DUP ( & zv , precv - > op2 . zv ) ;
2014-04-12 01:18:58 +08:00
zval_update_constant_ex ( & zv , 1 , fptr - > common . scope TSRMLS_CC ) ;
2014-04-30 22:32:42 +08:00
if ( Z_TYPE ( zv ) = = IS_FALSE ) {
memcpy ( offset , " false " , 5 ) ;
offset + = 5 ;
} else if ( Z_TYPE ( zv ) = = IS_TRUE ) {
memcpy ( offset , " true " , 4 ) ;
offset + = 4 ;
2014-02-10 14:04:30 +08:00
} else if ( Z_TYPE ( zv ) = = IS_NULL ) {
2011-09-23 23:08:11 +08:00
memcpy ( offset , " NULL " , 4 ) ;
offset + = 4 ;
2014-02-10 14:04:30 +08:00
} else if ( Z_TYPE ( zv ) = = IS_STRING ) {
2011-09-23 23:08:11 +08:00
* ( offset + + ) = ' \' ' ;
2014-02-10 14:04:30 +08:00
REALLOC_BUF_IF_EXCEED ( buf , offset , length , MIN ( Z_STRLEN ( zv ) , 10 ) ) ;
memcpy ( offset , Z_STRVAL ( zv ) , MIN ( Z_STRLEN ( zv ) , 10 ) ) ;
offset + = MIN ( Z_STRLEN ( zv ) , 10 ) ;
if ( Z_STRLEN ( zv ) > 10 ) {
2011-09-23 23:08:11 +08:00
* ( offset + + ) = ' . ' ;
* ( offset + + ) = ' . ' ;
* ( offset + + ) = ' . ' ;
}
* ( offset + + ) = ' \' ' ;
2014-02-10 14:04:30 +08:00
} else if ( Z_TYPE ( zv ) = = IS_ARRAY ) {
2011-10-31 11:47:11 +08:00
memcpy ( offset , " Array " , 5 ) ;
offset + = 5 ;
2011-09-23 23:08:11 +08:00
} else {
2014-04-21 23:51:15 +08:00
zend_string * str = zval_get_string ( & zv ) ;
REALLOC_BUF_IF_EXCEED ( buf , offset , length , str - > len ) ;
memcpy ( offset , str - > val , str - > len ) ;
offset + = str - > len ;
STR_RELEASE ( str ) ;
2011-09-23 23:08:11 +08:00
}
zval_ptr_dtor ( & zv ) ;
}
} else {
memcpy ( offset , " NULL " , 4 ) ;
offset + = 4 ;
}
}
if ( + + i < fptr - > common . num_args ) {
* ( offset + + ) = ' , ' ;
* ( offset + + ) = ' ' ;
}
arg_info + + ;
2011-10-31 11:47:11 +08:00
REALLOC_BUF_IF_EXCEED ( buf , offset , length , 32 ) ;
2011-09-23 23:08:11 +08:00
}
}
* ( offset + + ) = ' ) ' ;
* offset = ' \0 ' ;
return buf ;
2013-01-28 10:02:51 +08:00
}
2011-09-23 23:08:11 +08:00
/* }}} */
static void do_inheritance_check_on_method ( zend_function * child , zend_function * parent TSRMLS_DC ) /* { { { */
2002-12-07 01:09:44 +08:00
{
2003-02-04 20:12:34 +08:00
zend_uint child_flags ;
2011-01-20 01:17:52 +08:00
zend_uint parent_flags = parent - > common . fn_flags ;
2011-11-19 21:36:03 +08:00
if ( ( parent - > common . scope - > ce_flags & ZEND_ACC_INTERFACE ) = = 0
& & parent - > common . fn_flags & ZEND_ACC_ABSTRACT
2004-01-29 06:27:39 +08:00
& & parent - > common . scope ! = ( child - > common . prototype ? child - > common . prototype - > common . scope : child - > common . scope )
2004-01-28 18:25:45 +08:00
& & child - > common . fn_flags & ( ZEND_ACC_ABSTRACT | ZEND_ACC_IMPLEMENTED_ABSTRACT ) ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Can't inherit abstract function %s::%s() (previously declared abstract in %s) " ,
2014-02-21 21:35:19 +08:00
parent - > common . scope - > name - > val ,
child - > common . function_name - > val ,
child - > common . prototype ? child - > common . prototype - > common . scope - > name - > val : child - > common . scope - > name - > val ) ;
2004-01-28 18:25:45 +08:00
}
2003-02-24 20:05:58 +08:00
if ( parent_flags & ZEND_ACC_FINAL ) {
2014-02-21 21:27:53 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot override final method %s::%s() " , ZEND_FN_SCOPE_NAME ( parent ) , child - > common . function_name - > val ) ;
2003-02-24 20:05:58 +08:00
}
2003-02-04 20:12:34 +08:00
child_flags = child - > common . fn_flags ;
2002-11-24 04:44:12 +08:00
/* You cannot change from static to non static and vice versa.
*/
2002-12-07 01:09:44 +08:00
if ( ( child_flags & ZEND_ACC_STATIC ) ! = ( parent_flags & ZEND_ACC_STATIC ) ) {
if ( child - > common . fn_flags & ZEND_ACC_STATIC ) {
2014-02-21 21:35:19 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot make non static method %s::%s() static in class %s " , ZEND_FN_SCOPE_NAME ( parent ) , child - > common . function_name - > val , ZEND_FN_SCOPE_NAME ( child ) ) ;
2002-11-24 04:44:12 +08:00
} else {
2014-02-21 21:35:19 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot make static method %s::%s() non static in class %s " , ZEND_FN_SCOPE_NAME ( parent ) , child - > common . function_name - > val , ZEND_FN_SCOPE_NAME ( child ) ) ;
2002-11-24 04:44:12 +08:00
}
}
2002-12-08 05:46:12 +08:00
2003-02-23 21:58:48 +08:00
/* Disallow making an inherited method abstract. */
2002-12-08 05:46:12 +08:00
if ( ( child_flags & ZEND_ACC_ABSTRACT ) & & ! ( parent_flags & ZEND_ACC_ABSTRACT ) ) {
2014-02-21 21:35:19 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot make non abstract method %s::%s() abstract in class %s " , ZEND_FN_SCOPE_NAME ( parent ) , child - > common . function_name - > val , ZEND_FN_SCOPE_NAME ( child ) ) ;
2002-11-24 04:44:12 +08:00
}
2002-12-09 20:10:17 +08:00
2003-01-02 21:58:08 +08:00
if ( parent_flags & ZEND_ACC_CHANGED ) {
child - > common . fn_flags | = ZEND_ACC_CHANGED ;
} else {
/* Prevent derived classes from restricting access that was available in parent classes
*/
if ( ( child_flags & ZEND_ACC_PPP_MASK ) > ( parent_flags & ZEND_ACC_PPP_MASK ) ) {
2014-02-21 21:35:19 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Access level to %s::%s() must be %s (as in class %s)%s " , ZEND_FN_SCOPE_NAME ( child ) , child - > common . function_name - > val , zend_visibility_string ( parent_flags ) , ZEND_FN_SCOPE_NAME ( parent ) , ( parent_flags & ZEND_ACC_PUBLIC ) ? " " : " or weaker " ) ;
2006-05-12 05:07:39 +08:00
} else if ( ( ( child_flags & ZEND_ACC_PPP_MASK ) < ( parent_flags & ZEND_ACC_PPP_MASK ) )
2003-01-02 21:58:08 +08:00
& & ( ( parent_flags & ZEND_ACC_PPP_MASK ) & ZEND_ACC_PRIVATE ) ) {
child - > common . fn_flags | = ZEND_ACC_CHANGED ;
}
2002-12-09 20:10:17 +08:00
}
2002-12-27 00:27:59 +08:00
2006-09-12 19:01:16 +08:00
if ( parent_flags & ZEND_ACC_PRIVATE ) {
2013-01-28 10:02:51 +08:00
child - > common . prototype = NULL ;
2006-09-12 19:01:16 +08:00
} else if ( parent_flags & ZEND_ACC_ABSTRACT ) {
2004-03-01 02:25:50 +08:00
child - > common . fn_flags | = ZEND_ACC_IMPLEMENTED_ABSTRACT ;
2004-04-21 16:44:37 +08:00
child - > common . prototype = parent ;
2006-05-31 07:10:28 +08:00
} else if ( ! ( parent - > common . fn_flags & ZEND_ACC_CTOR ) | | ( parent - > common . prototype & & ( parent - > common . prototype - > common . scope - > ce_flags & ZEND_ACC_INTERFACE ) ) ) {
2006-05-30 04:06:43 +08:00
/* ctors only have a prototype if it comes from an interface */
child - > common . prototype = parent - > common . prototype ? parent - > common . prototype : parent ;
2003-03-29 19:19:38 +08:00
}
2006-05-31 07:10:28 +08:00
if ( child - > common . prototype & & ( child - > common . prototype - > common . fn_flags & ZEND_ACC_ABSTRACT ) ) {
2011-06-14 01:52:23 +08:00
if ( ! zend_do_perform_implementation_check ( child , child - > common . prototype TSRMLS_CC ) ) {
2014-02-21 21:35:19 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Declaration of %s::%s() must be compatible with %s " , ZEND_FN_SCOPE_NAME ( child ) , child - > common . function_name - > val , zend_get_function_declaration ( child - > common . prototype TSRMLS_CC ) ) ;
2004-04-21 16:44:37 +08:00
}
2014-02-10 14:04:30 +08:00
} else if ( EG ( error_reporting ) & E_STRICT | | Z_TYPE ( EG ( user_error_handler ) ) ! = IS_UNDEF ) { /* Check E_STRICT (or custom error handler) before the check so that we save some time */
2011-06-14 01:52:23 +08:00
if ( ! zend_do_perform_implementation_check ( child , parent TSRMLS_CC ) ) {
2013-06-10 21:26:11 +08:00
char * method_prototype = zend_get_function_declaration ( parent TSRMLS_CC ) ;
2014-02-10 14:04:30 +08:00
zend_error ( E_STRICT , " Declaration of %s::%s() should be compatible with %s " , ZEND_FN_SCOPE_NAME ( child ) , child - > common . function_name - > val , method_prototype ) ;
2011-09-23 23:08:11 +08:00
efree ( method_prototype ) ;
2004-03-01 02:25:50 +08:00
}
2003-03-29 19:19:38 +08:00
}
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
}
2011-09-23 23:08:11 +08:00
/* }}} */
2003-03-29 19:19:38 +08:00
2014-05-27 01:29:35 +08:00
static zend_bool do_inherit_method_check ( HashTable * child_function_table , zend_function * parent , zend_string * key , zend_class_entry * child_ce ) /* { { { */
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
{
zend_uint parent_flags = parent - > common . fn_flags ;
zend_function * child ;
TSRMLS_FETCH ( ) ;
2014-05-27 01:29:35 +08:00
if ( ( child = zend_hash_find_ptr ( child_function_table , key ) ) = = NULL ) {
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
if ( parent_flags & ( ZEND_ACC_ABSTRACT ) ) {
child_ce - > ce_flags | = ZEND_ACC_IMPLICIT_ABSTRACT_CLASS ;
}
return 1 ; /* method doesn't exist in child, copy from parent */
}
2013-01-28 10:02:51 +08:00
2010-04-23 07:16:15 +08:00
do_inheritance_check_on_method ( child , parent TSRMLS_CC ) ;
2013-01-28 10:02:51 +08:00
2002-12-27 00:27:59 +08:00
return 0 ;
2002-11-24 04:44:12 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2002-11-24 04:44:12 +08:00
2014-05-27 01:29:35 +08:00
static zend_bool do_inherit_property_access_check ( HashTable * target_ht , zend_property_info * parent_info , zend_string * key , zend_class_entry * ce ) /* { { { */
2003-02-04 20:12:34 +08:00
{
zend_property_info * child_info ;
zend_class_entry * parent_ce = ce - > parent ;
2005-06-10 01:20:44 +08:00
if ( parent_info - > flags & ( ZEND_ACC_PRIVATE | ZEND_ACC_SHADOW ) ) {
2014-05-27 01:29:35 +08:00
if ( ( child_info = zend_hash_find_ptr ( & ce - > properties_info , key ) ) ! = NULL ) {
2003-09-09 07:25:57 +08:00
child_info - > flags | = ZEND_ACC_CHANGED ;
2005-06-10 01:20:44 +08:00
} else {
if ( ce - > type & ZEND_INTERNAL_CLASS ) {
2014-05-27 01:29:35 +08:00
child_info = zend_duplicate_property_info_internal ( parent_info ) ;
2005-06-10 01:20:44 +08:00
} else {
2014-05-27 01:29:35 +08:00
child_info = zend_duplicate_property_info ( parent_info ) ;
2005-06-10 01:20:44 +08:00
}
2014-05-27 01:29:35 +08:00
zend_hash_update_ptr ( & ce - > properties_info , key , child_info ) ;
2005-06-10 01:20:44 +08:00
child_info - > flags & = ~ ZEND_ACC_PRIVATE ; /* it's not private anymore */
child_info - > flags | = ZEND_ACC_SHADOW ; /* but it's a shadow of private */
2003-03-19 00:30:23 +08:00
}
2003-02-04 20:12:34 +08:00
return 0 ; /* don't copy access information to child */
}
2014-05-27 01:29:35 +08:00
if ( ( child_info = zend_hash_find_ptr ( & ce - > properties_info , key ) ) ! = NULL ) {
2003-09-04 03:28:46 +08:00
if ( ( parent_info - > flags & ZEND_ACC_STATIC ) ! = ( child_info - > flags & ZEND_ACC_STATIC ) ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot redeclare %s%s::$%s as %s%s::$%s " ,
2014-05-27 01:29:35 +08:00
( parent_info - > flags & ZEND_ACC_STATIC ) ? " static " : " non static " , parent_ce - > name - > val , key - > val ,
( child_info - > flags & ZEND_ACC_STATIC ) ? " static " : " non static " , ce - > name - > val , key - > val ) ;
2013-01-28 10:02:51 +08:00
2003-09-04 03:28:46 +08:00
}
2006-05-12 05:07:39 +08:00
2005-06-10 01:20:44 +08:00
if ( parent_info - > flags & ZEND_ACC_CHANGED ) {
child_info - > flags | = ZEND_ACC_CHANGED ;
}
2006-05-12 05:07:39 +08:00
2003-02-04 20:12:34 +08:00
if ( ( child_info - > flags & ZEND_ACC_PPP_MASK ) > ( parent_info - > flags & ZEND_ACC_PPP_MASK ) ) {
2014-05-27 01:29:35 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Access level to %s::$%s must be %s (as in class %s)%s " , ce - > name - > val , key - > val , zend_visibility_string ( parent_info - > flags ) , parent_ce - > name - > val , ( parent_info - > flags & ZEND_ACC_PUBLIC ) ? " " : " or weaker " ) ;
2010-05-24 22:11:39 +08:00
} else if ( ( child_info - > flags & ZEND_ACC_STATIC ) = = 0 ) {
2012-12-10 20:29:51 +08:00
zval_ptr_dtor ( & ( ce - > default_properties_table [ parent_info - > offset ] ) ) ;
2010-05-24 22:11:39 +08:00
ce - > default_properties_table [ parent_info - > offset ] = ce - > default_properties_table [ child_info - > offset ] ;
2014-02-10 14:04:30 +08:00
ZVAL_UNDEF ( & ce - > default_properties_table [ child_info - > offset ] ) ;
2010-05-24 22:11:39 +08:00
child_info - > offset = parent_info - > offset ;
2003-02-04 20:12:34 +08:00
}
return 0 ; /* Don't copy from parent */
} else {
return 1 ; /* Copy from parent */
}
}
2009-07-27 22:11:53 +08:00
/* }}} */
2003-02-04 20:12:34 +08:00
2009-07-27 22:11:53 +08:00
static inline void do_implement_interface ( zend_class_entry * ce , zend_class_entry * iface TSRMLS_DC ) /* { { { */
2003-05-30 03:00:40 +08:00
{
2003-12-07 03:02:12 +08:00
if ( ! ( ce - > ce_flags & ZEND_ACC_INTERFACE ) & & iface - > interface_gets_implemented & & iface - > interface_gets_implemented ( iface , ce TSRMLS_CC ) = = FAILURE ) {
2014-02-10 14:04:30 +08:00
zend_error ( E_CORE_ERROR , " Class %s could not implement interface %s " , ce - > name - > val , iface - > name - > val ) ;
2003-10-23 03:59:58 +08:00
}
2004-12-06 19:53:30 +08:00
if ( ce = = iface ) {
2014-02-10 14:04:30 +08:00
zend_error ( E_ERROR , " Interface %s cannot implement itself " , ce - > name - > val ) ;
2004-12-06 19:53:30 +08:00
}
2003-10-23 03:59:58 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2003-05-30 03:00:40 +08:00
2009-07-27 22:11:53 +08:00
ZEND_API void zend_do_inherit_interfaces ( zend_class_entry * ce , const zend_class_entry * iface TSRMLS_DC ) /* { { { */
2003-10-23 03:59:58 +08:00
{
/* expects interface to be contained in ce's interface list already */
2004-09-27 16:46:12 +08:00
zend_uint i , ce_num , if_num = iface - > num_interfaces ;
2003-10-23 03:59:58 +08:00
zend_class_entry * entry ;
2004-01-28 17:13:41 +08:00
if ( if_num = = 0 ) {
return ;
}
ce_num = ce - > num_interfaces ;
2003-10-23 03:59:58 +08:00
2004-01-28 17:13:41 +08:00
if ( ce - > type = = ZEND_INTERNAL_CLASS ) {
ce - > interfaces = ( zend_class_entry * * ) realloc ( ce - > interfaces , sizeof ( zend_class_entry * ) * ( ce_num + if_num ) ) ;
} else {
ce - > interfaces = ( zend_class_entry * * ) erealloc ( ce - > interfaces , sizeof ( zend_class_entry * ) * ( ce_num + if_num ) ) ;
}
/* Inherit the interfaces, only if they're not already inherited by the class */
while ( if_num - - ) {
entry = iface - > interfaces [ if_num ] ;
for ( i = 0 ; i < ce_num ; i + + ) {
if ( ce - > interfaces [ i ] = = entry ) {
break ;
2003-10-23 03:59:58 +08:00
}
}
2004-01-28 17:13:41 +08:00
if ( i = = ce_num ) {
ce - > interfaces [ ce - > num_interfaces + + ] = entry ;
2003-05-30 03:00:40 +08:00
}
}
2004-01-28 17:13:41 +08:00
/* and now call the implementing handlers */
while ( ce_num < ce - > num_interfaces ) {
do_implement_interface ( ce , ce - > interfaces [ ce_num + + ] TSRMLS_CC ) ;
}
2003-05-30 03:00:40 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2003-05-30 03:00:40 +08:00
2010-08-11 17:38:41 +08:00
# ifdef ZTS
# define zval_property_ctor(parent_ce, ce) \
2014-04-09 21:51:28 +08:00
( ( ( parent_ce ) - > type ! = ( ce ) - > type ) ? ZVAL_COPY_CTOR : zval_add_ref )
2010-08-11 17:38:41 +08:00
# else
# define zval_property_ctor(parent_ce, ce) \
2014-02-10 14:04:30 +08:00
zval_add_ref
2010-08-11 17:38:41 +08:00
# endif
2014-06-17 01:11:52 +08:00
static void do_inherit_class_constant ( zend_string * name , zval * zv , zend_class_entry * ce , zend_class_entry * parent_ce TSRMLS_DC ) /* { { { */
2014-04-14 17:24:43 +08:00
{
2014-06-17 01:11:52 +08:00
if ( ! Z_ISREF_P ( zv ) ) {
if ( parent_ce - > type = = ZEND_INTERNAL_CLASS ) {
ZVAL_NEW_PERSISTENT_REF ( zv , zv ) ;
} else {
ZVAL_NEW_REF ( zv , zv ) ;
2014-04-14 17:24:43 +08:00
}
}
2014-06-17 03:32:58 +08:00
if ( Z_CONSTANT_P ( Z_REFVAL_P ( zv ) ) ) {
ce - > ce_flags & = ~ ZEND_ACC_CONSTANTS_UPDATED ;
}
2014-06-17 01:11:52 +08:00
if ( zend_hash_add ( & ce - > constants_table , name , zv ) ) {
Z_ADDREF_P ( zv ) ;
}
2014-04-14 17:24:43 +08:00
}
/* }}} */
2009-07-27 22:11:53 +08:00
ZEND_API void zend_do_inheritance ( zend_class_entry * ce , zend_class_entry * parent_ce TSRMLS_DC ) /* { { { */
2000-06-09 22:40:14 +08:00
{
2010-05-24 22:11:39 +08:00
zend_property_info * property_info ;
2014-05-27 01:29:35 +08:00
zend_function * func ;
zend_string * key ;
2014-06-17 01:11:52 +08:00
zval * zv ;
2010-05-24 22:11:39 +08:00
2003-03-05 19:14:44 +08:00
if ( ( ce - > ce_flags & ZEND_ACC_INTERFACE )
& & ! ( parent_ce - > ce_flags & ZEND_ACC_INTERFACE ) ) {
2014-02-21 22:23:56 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Interface %s may not inherit from class (%s) " , ce - > name - > val , parent_ce - > name - > val ) ;
2003-03-05 19:14:44 +08:00
}
2003-06-22 05:56:06 +08:00
if ( parent_ce - > ce_flags & ZEND_ACC_FINAL_CLASS ) {
2014-02-21 22:23:56 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Class %s may not inherit from final class (%s) " , ce - > name - > val , parent_ce - > name - > val ) ;
2003-06-22 05:56:06 +08:00
}
2003-03-05 19:14:44 +08:00
2003-02-04 20:12:34 +08:00
ce - > parent = parent_ce ;
2008-08-25 02:22:33 +08:00
/* Copy serialize/unserialize callbacks */
if ( ! ce - > serialize ) {
ce - > serialize = parent_ce - > serialize ;
}
if ( ! ce - > unserialize ) {
ce - > unserialize = parent_ce - > unserialize ;
}
2003-05-30 03:00:40 +08:00
/* Inherit interfaces */
2003-10-23 03:59:58 +08:00
zend_do_inherit_interfaces ( ce , parent_ce TSRMLS_CC ) ;
2000-06-09 22:40:14 +08:00
2003-02-04 20:12:34 +08:00
/* Inherit properties */
2010-05-24 22:11:39 +08:00
if ( parent_ce - > default_properties_count ) {
int i = ce - > default_properties_count + parent_ce - > default_properties_count ;
2014-02-17 15:50:32 +08:00
ce - > default_properties_table = perealloc ( ce - > default_properties_table , sizeof ( zval ) * i , ce - > type = = ZEND_INTERNAL_CLASS ) ;
2010-05-24 22:11:39 +08:00
if ( ce - > default_properties_count ) {
while ( i - - > parent_ce - > default_properties_count ) {
ce - > default_properties_table [ i ] = ce - > default_properties_table [ i - parent_ce - > default_properties_count ] ;
}
}
for ( i = 0 ; i < parent_ce - > default_properties_count ; i + + ) {
2010-08-11 17:38:41 +08:00
# ifdef ZTS
2014-04-09 21:51:28 +08:00
if ( parent_ce - > type ! = ce - > type ) {
ZVAL_DUP ( & ce - > default_properties_table [ i ] , & parent_ce - > default_properties_table [ i ] ) ;
2014-06-17 03:32:58 +08:00
if ( Z_OPT_CONSTANT ( ce - > default_properties_table [ i ] ) ) {
ce - > ce_flags & = ~ ZEND_ACC_CONSTANTS_UPDATED ;
}
2014-04-09 21:51:28 +08:00
continue ;
2010-05-24 22:11:39 +08:00
}
2014-04-09 21:51:28 +08:00
# endif
ZVAL_COPY ( & ce - > default_properties_table [ i ] , & parent_ce - > default_properties_table [ i ] ) ;
2014-06-17 03:32:58 +08:00
if ( Z_OPT_CONSTANT ( ce - > default_properties_table [ i ] ) ) {
ce - > ce_flags & = ~ ZEND_ACC_CONSTANTS_UPDATED ;
}
2010-05-24 22:11:39 +08:00
}
ce - > default_properties_count + = parent_ce - > default_properties_count ;
}
2005-09-01 18:05:32 +08:00
if ( parent_ce - > type ! = ce - > type ) {
/* User class extends internal class */
zend_update_class_constants ( parent_ce TSRMLS_CC ) ;
2010-05-24 22:11:39 +08:00
if ( parent_ce - > default_static_members_count ) {
int i = ce - > default_static_members_count + parent_ce - > default_static_members_count ;
2014-02-22 03:51:08 +08:00
ce - > default_static_members_table = erealloc ( ce - > default_static_members_table , sizeof ( zval ) * i ) ;
2010-05-24 22:11:39 +08:00
if ( ce - > default_static_members_count ) {
while ( i - - > parent_ce - > default_static_members_count ) {
ce - > default_static_members_table [ i ] = ce - > default_static_members_table [ i - parent_ce - > default_static_members_count ] ;
}
}
for ( i = 0 ; i < parent_ce - > default_static_members_count ; i + + ) {
2014-06-05 20:04:11 +08:00
ZVAL_MAKE_REF ( & CE_STATIC_MEMBERS ( parent_ce ) [ i ] ) ;
2010-05-24 22:11:39 +08:00
ce - > default_static_members_table [ i ] = CE_STATIC_MEMBERS ( parent_ce ) [ i ] ;
2014-02-10 14:04:30 +08:00
Z_ADDREF ( ce - > default_static_members_table [ i ] ) ;
2014-06-17 03:32:58 +08:00
if ( Z_CONSTANT_P ( Z_REFVAL ( ce - > default_static_members_table [ i ] ) ) ) {
ce - > ce_flags & = ~ ZEND_ACC_CONSTANTS_UPDATED ;
}
2010-05-24 22:11:39 +08:00
}
ce - > default_static_members_count + = parent_ce - > default_static_members_count ;
ce - > static_members_table = ce - > default_static_members_table ;
}
2005-09-01 18:05:32 +08:00
} else {
2010-05-24 22:11:39 +08:00
if ( parent_ce - > default_static_members_count ) {
int i = ce - > default_static_members_count + parent_ce - > default_static_members_count ;
2014-02-22 03:51:08 +08:00
ce - > default_static_members_table = perealloc ( ce - > default_static_members_table , sizeof ( zval ) * i , ce - > type = = ZEND_INTERNAL_CLASS ) ;
2010-05-24 22:11:39 +08:00
if ( ce - > default_static_members_count ) {
while ( i - - > parent_ce - > default_static_members_count ) {
ce - > default_static_members_table [ i ] = ce - > default_static_members_table [ i - parent_ce - > default_static_members_count ] ;
}
}
for ( i = 0 ; i < parent_ce - > default_static_members_count ; i + + ) {
2014-06-05 20:04:11 +08:00
ZVAL_MAKE_REF ( & parent_ce - > default_static_members_table [ i ] ) ;
2010-05-24 22:11:39 +08:00
ce - > default_static_members_table [ i ] = parent_ce - > default_static_members_table [ i ] ;
2014-02-10 14:04:30 +08:00
Z_ADDREF ( ce - > default_static_members_table [ i ] ) ;
2014-06-17 03:32:58 +08:00
if ( Z_CONSTANT_P ( Z_REFVAL ( ce - > default_static_members_table [ i ] ) ) ) {
ce - > ce_flags & = ~ ZEND_ACC_CONSTANTS_UPDATED ;
}
2010-05-24 22:11:39 +08:00
}
ce - > default_static_members_count + = parent_ce - > default_static_members_count ;
if ( ce - > type = = ZEND_USER_CLASS ) {
ce - > static_members_table = ce - > default_static_members_table ;
}
}
2005-09-01 18:05:32 +08:00
}
2011-01-20 01:17:52 +08:00
2014-04-18 23:18:11 +08:00
ZEND_HASH_FOREACH_PTR ( & ce - > properties_info , property_info ) {
2010-05-24 22:11:39 +08:00
if ( property_info - > ce = = ce ) {
if ( property_info - > flags & ZEND_ACC_STATIC ) {
property_info - > offset + = parent_ce - > default_static_members_count ;
} else {
property_info - > offset + = parent_ce - > default_properties_count ;
}
}
2014-04-18 23:18:11 +08:00
} ZEND_HASH_FOREACH_END ( ) ;
2010-05-24 22:11:39 +08:00
2014-05-27 01:29:35 +08:00
ZEND_HASH_FOREACH_STR_KEY_PTR ( & parent_ce - > properties_info , key , property_info ) {
if ( do_inherit_property_access_check ( & ce - > properties_info , property_info , key , ce ) ) {
if ( ce - > type & ZEND_INTERNAL_CLASS ) {
property_info = zend_duplicate_property_info_internal ( property_info ) ;
} else {
property_info = zend_duplicate_property_info ( property_info ) ;
}
zend_hash_add_new_ptr ( & ce - > properties_info , key , property_info ) ;
}
} ZEND_HASH_FOREACH_END ( ) ;
2002-07-16 02:09:56 +08:00
2014-06-17 01:11:52 +08:00
ZEND_HASH_FOREACH_STR_KEY_VAL ( & parent_ce - > constants_table , key , zv ) {
do_inherit_class_constant ( key , zv , ce , parent_ce TSRMLS_CC ) ;
} ZEND_HASH_FOREACH_END ( ) ;
2014-05-27 01:29:35 +08:00
ZEND_HASH_FOREACH_STR_KEY_PTR ( & parent_ce - > function_table , key , func ) {
if ( do_inherit_method_check ( & ce - > function_table , func , key , ce ) ) {
zend_function * new_func = do_inherit_method ( func ) ;
zend_hash_add_new_ptr ( & ce - > function_table , key , new_func ) ;
}
} ZEND_HASH_FOREACH_END ( ) ;
2000-06-09 22:40:14 +08:00
do_inherit_parent_constructor ( ce ) ;
2006-05-12 05:07:39 +08:00
if ( ce - > ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS & & ce - > type = = ZEND_INTERNAL_CLASS ) {
ce - > ce_flags | = ZEND_ACC_EXPLICIT_ABSTRACT_CLASS ;
2012-12-25 14:23:08 +08:00
} else if ( ! ( ce - > ce_flags & ( ZEND_ACC_IMPLEMENT_INTERFACES | ZEND_ACC_IMPLEMENT_TRAITS ) ) ) {
2008-03-12 17:46:42 +08:00
/* The verification will be done in runtime by ZEND_VERIFY_ABSTRACT_CLASS */
2006-05-12 05:07:39 +08:00
zend_verify_abstract_class ( ce TSRMLS_CC ) ;
}
2010-07-06 19:40:17 +08:00
ce - > ce_flags | = parent_ce - > ce_flags & ZEND_HAS_STATIC_IN_METHODS ;
2000-06-09 22:40:14 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2000-06-09 22:40:14 +08:00
2014-06-17 01:11:52 +08:00
static zend_bool do_inherit_constant_check ( HashTable * child_constants_table , zval * parent_constant , zend_string * name , const zend_class_entry * iface ) /* { { { */
2004-01-28 19:53:52 +08:00
{
2014-02-10 14:04:30 +08:00
zval * old_constant ;
2005-11-23 17:26:43 +08:00
2014-06-17 01:11:52 +08:00
if ( ( old_constant = zend_hash_find ( child_constants_table , name ) ) ! = NULL ) {
2014-04-14 17:24:43 +08:00
if ( ! Z_ISREF_P ( old_constant ) | |
! Z_ISREF_P ( parent_constant ) | |
Z_REFVAL_P ( old_constant ) ! = Z_REFVAL_P ( parent_constant ) ) {
2014-06-17 01:11:52 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot inherit previously-inherited or override constant %s from interface %s " , name - > val , iface - > name - > val ) ;
2005-11-23 17:26:43 +08:00
}
2006-05-10 07:53:23 +08:00
return 0 ;
2004-01-28 19:53:52 +08:00
}
return 1 ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
2004-01-28 19:53:52 +08:00
2014-06-17 01:11:52 +08:00
static void do_inherit_iface_constant ( zend_string * name , zval * zv , zend_class_entry * ce , zend_class_entry * iface TSRMLS_DC ) /* { { { */
2014-04-14 17:24:43 +08:00
{
2014-06-17 01:11:52 +08:00
if ( do_inherit_constant_check ( & ce - > constants_table , zv , name , iface ) ) {
2014-06-05 20:04:11 +08:00
ZVAL_MAKE_REF ( zv ) ;
2014-04-14 17:24:43 +08:00
Z_ADDREF_P ( zv ) ;
2014-06-17 01:11:52 +08:00
zend_hash_update ( & ce - > constants_table , name , zv ) ;
2014-04-14 17:24:43 +08:00
}
}
/* }}} */
2009-07-27 22:11:53 +08:00
ZEND_API void zend_do_implement_interface ( zend_class_entry * ce , zend_class_entry * iface TSRMLS_DC ) /* { { { */
2003-03-05 19:14:44 +08:00
{
2006-06-07 17:21:06 +08:00
zend_uint i , ignore = 0 ;
zend_uint current_iface_num = ce - > num_interfaces ;
zend_uint parent_iface_num = ce - > parent ? ce - > parent - > num_interfaces : 0 ;
2014-05-27 01:29:35 +08:00
zend_function * func ;
zend_string * key ;
2014-06-17 01:11:52 +08:00
zval * zv ;
2006-06-07 17:21:06 +08:00
for ( i = 0 ; i < ce - > num_interfaces ; i + + ) {
if ( ce - > interfaces [ i ] = = NULL ) {
memmove ( ce - > interfaces + i , ce - > interfaces + i + 1 , sizeof ( zend_class_entry * ) * ( - - ce - > num_interfaces - i ) ) ;
i - - ;
} else if ( ce - > interfaces [ i ] = = iface ) {
if ( i < parent_iface_num ) {
ignore = 1 ;
} else {
2014-02-21 22:23:56 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Class %s cannot implement previously implemented interface %s " , ce - > name - > val , iface - > name - > val ) ;
2006-06-07 17:21:06 +08:00
}
}
}
2009-12-03 20:34:50 +08:00
if ( ignore ) {
/* Check for attempt to redeclare interface constants */
2014-06-17 01:11:52 +08:00
ZEND_HASH_FOREACH_STR_KEY_VAL ( & ce - > constants_table , key , zv ) {
do_inherit_constant_check ( & iface - > constants_table , zv , key , iface ) ;
} ZEND_HASH_FOREACH_END ( ) ;
2009-12-03 20:34:50 +08:00
} else {
2006-06-07 17:21:06 +08:00
if ( ce - > num_interfaces > = current_iface_num ) {
if ( ce - > type = = ZEND_INTERNAL_CLASS ) {
ce - > interfaces = ( zend_class_entry * * ) realloc ( ce - > interfaces , sizeof ( zend_class_entry * ) * ( + + current_iface_num ) ) ;
} else {
ce - > interfaces = ( zend_class_entry * * ) erealloc ( ce - > interfaces , sizeof ( zend_class_entry * ) * ( + + current_iface_num ) ) ;
}
}
ce - > interfaces [ ce - > num_interfaces + + ] = iface ;
2013-01-28 10:02:51 +08:00
2014-06-17 01:11:52 +08:00
ZEND_HASH_FOREACH_STR_KEY_VAL ( & iface - > constants_table , key , zv ) {
do_inherit_iface_constant ( key , zv , ce , iface TSRMLS_CC ) ;
} ZEND_HASH_FOREACH_END ( ) ;
2014-05-27 01:29:35 +08:00
ZEND_HASH_FOREACH_STR_KEY_PTR ( & iface - > function_table , key , func ) {
if ( do_inherit_method_check ( & ce - > function_table , func , key , ce ) ) {
zend_function * new_func = do_inherit_method ( func ) ;
zend_hash_add_new_ptr ( & ce - > function_table , key , new_func ) ;
}
} ZEND_HASH_FOREACH_END ( ) ;
2013-01-28 10:02:51 +08:00
2006-06-07 17:21:06 +08:00
do_implement_interface ( ce , iface TSRMLS_CC ) ;
zend_do_inherit_interfaces ( ce , iface TSRMLS_CC ) ;
}
2003-03-05 19:14:44 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2003-03-05 19:14:44 +08:00
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
ZEND_API void zend_do_implement_trait ( zend_class_entry * ce , zend_class_entry * trait TSRMLS_DC ) /* { { { */
{
zend_uint i , ignore = 0 ;
zend_uint current_trait_num = ce - > num_traits ;
zend_uint parent_trait_num = ce - > parent ? ce - > parent - > num_traits : 0 ;
for ( i = 0 ; i < ce - > num_traits ; i + + ) {
if ( ce - > traits [ i ] = = NULL ) {
memmove ( ce - > traits + i , ce - > traits + i + 1 , sizeof ( zend_class_entry * ) * ( - - ce - > num_traits - i ) ) ;
i - - ;
} else if ( ce - > traits [ i ] = = trait ) {
if ( i < parent_trait_num ) {
ignore = 1 ;
}
}
}
if ( ! ignore ) {
if ( ce - > num_traits > = current_trait_num ) {
if ( ce - > type = = ZEND_INTERNAL_CLASS ) {
ce - > traits = ( zend_class_entry * * ) realloc ( ce - > traits , sizeof ( zend_class_entry * ) * ( + + current_trait_num ) ) ;
} else {
ce - > traits = ( zend_class_entry * * ) erealloc ( ce - > traits , sizeof ( zend_class_entry * ) * ( + + current_trait_num ) ) ;
}
}
ce - > traits [ ce - > num_traits + + ] = trait ;
}
}
/* }}} */
2012-03-05 02:26:11 +08:00
static zend_bool zend_traits_method_compatibility_check ( zend_function * fn , zend_function * other_fn TSRMLS_DC ) /* { { { */
{
zend_uint fn_flags = fn - > common . scope - > ce_flags ;
zend_uint other_flags = other_fn - > common . scope - > ce_flags ;
2013-01-28 10:02:51 +08:00
2012-03-05 02:26:11 +08:00
return zend_do_perform_implementation_check ( fn , other_fn TSRMLS_CC )
2013-03-19 16:48:23 +08:00
& & ( ( other_fn - > common . scope - > ce_flags & ZEND_ACC_INTERFACE ) | | zend_do_perform_implementation_check ( other_fn , fn TSRMLS_CC ) )
2013-01-28 10:02:51 +08:00
& & ( ( fn_flags & ( ZEND_ACC_FINAL | ZEND_ACC_STATIC ) ) = =
2012-12-25 14:23:08 +08:00
( other_flags & ( ZEND_ACC_FINAL | ZEND_ACC_STATIC ) ) ) ; /* equal final and static qualifier */
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
}
/* }}} */
2014-02-10 14:04:30 +08:00
static void zend_add_magic_methods ( zend_class_entry * ce , zend_string * mname , zend_function * fe TSRMLS_DC ) /* { { { */
2011-11-03 05:12:13 +08:00
{
2014-02-10 14:04:30 +08:00
if ( ! strncmp ( mname - > val , ZEND_CLONE_FUNC_NAME , mname - > len ) ) {
2011-11-03 05:12:13 +08:00
ce - > clone = fe ; fe - > common . fn_flags | = ZEND_ACC_CLONE ;
2014-02-10 14:04:30 +08:00
} else if ( ! strncmp ( mname - > val , ZEND_CONSTRUCTOR_FUNC_NAME , mname - > len ) ) {
2011-10-09 19:13:27 +08:00
if ( ce - > constructor ) {
2014-02-25 05:18:06 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " %s has colliding constructor definitions coming from traits " , ce - > name - > val ) ;
2011-10-09 19:13:27 +08:00
}
2013-01-28 10:02:51 +08:00
ce - > constructor = fe ; fe - > common . fn_flags | = ZEND_ACC_CTOR ;
2014-02-10 14:04:30 +08:00
} else if ( ! strncmp ( mname - > val , ZEND_DESTRUCTOR_FUNC_NAME , mname - > len ) ) {
2011-11-18 21:56:41 +08:00
ce - > destructor = fe ; fe - > common . fn_flags | = ZEND_ACC_DTOR ;
2014-02-10 14:04:30 +08:00
} else if ( ! strncmp ( mname - > val , ZEND_GET_FUNC_NAME , mname - > len ) ) {
2011-11-18 21:56:41 +08:00
ce - > __get = fe ;
2014-02-10 14:04:30 +08:00
} else if ( ! strncmp ( mname - > val , ZEND_SET_FUNC_NAME , mname - > len ) ) {
2011-11-18 21:56:41 +08:00
ce - > __set = fe ;
2014-02-10 14:04:30 +08:00
} else if ( ! strncmp ( mname - > val , ZEND_CALL_FUNC_NAME , mname - > len ) ) {
2011-11-18 21:56:41 +08:00
ce - > __call = fe ;
2014-02-10 14:04:30 +08:00
} else if ( ! strncmp ( mname - > val , ZEND_UNSET_FUNC_NAME , mname - > len ) ) {
2011-11-18 21:56:41 +08:00
ce - > __unset = fe ;
2014-02-10 14:04:30 +08:00
} else if ( ! strncmp ( mname - > val , ZEND_ISSET_FUNC_NAME , mname - > len ) ) {
2011-11-18 21:56:41 +08:00
ce - > __isset = fe ;
2014-02-10 14:04:30 +08:00
} else if ( ! strncmp ( mname - > val , ZEND_CALLSTATIC_FUNC_NAME , mname - > len ) ) {
2011-11-18 21:56:41 +08:00
ce - > __callstatic = fe ;
2014-02-10 14:04:30 +08:00
} else if ( ! strncmp ( mname - > val , ZEND_TOSTRING_FUNC_NAME , mname - > len ) ) {
2011-11-18 21:56:41 +08:00
ce - > __tostring = fe ;
2014-04-26 04:32:51 +08:00
} else if ( ! strncmp ( mname - > val , ZEND_DEBUGINFO_FUNC_NAME , mname - > len ) ) {
2014-02-18 11:13:00 +08:00
ce - > __debugInfo = fe ;
2014-02-25 05:18:06 +08:00
} else if ( ce - > name - > len = = mname - > len ) {
2014-02-10 14:04:30 +08:00
zend_string * lowercase_name = STR_ALLOC ( ce - > name - > len , 0 ) ;
zend_str_tolower_copy ( lowercase_name - > val , ce - > name - > val , ce - > name - > len ) ;
lowercase_name = zend_new_interned_string ( lowercase_name TSRMLS_CC ) ;
if ( ! memcmp ( mname - > val , lowercase_name - > val , mname - > len ) ) {
2011-10-09 19:13:27 +08:00
if ( ce - > constructor ) {
2014-02-25 05:18:06 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " %s has colliding constructor definitions coming from traits " , ce - > name - > val ) ;
2011-10-09 19:13:27 +08:00
}
ce - > constructor = fe ;
fe - > common . fn_flags | = ZEND_ACC_CTOR ;
}
2014-02-10 14:04:30 +08:00
STR_RELEASE ( lowercase_name ) ;
2011-10-09 19:13:27 +08:00
}
}
2011-11-03 05:12:13 +08:00
/* }}} */
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
2014-02-10 14:04:30 +08:00
static void zend_add_trait_method ( zend_class_entry * ce , const char * name , zend_string * key , zend_function * fn , HashTable * * overriden TSRMLS_DC ) /* { { { */
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
{
2012-12-25 14:23:08 +08:00
zend_function * existing_fn = NULL ;
2011-11-05 10:05:28 +08:00
2014-02-10 14:04:30 +08:00
if ( ( existing_fn = zend_hash_find_ptr ( & ce - > function_table , key ) ) ! = NULL ) {
2012-12-25 14:23:08 +08:00
if ( existing_fn - > common . scope = = ce ) {
/* members from the current class override trait methods */
/* use temporary *overriden HashTable to detect hidden conflict */
if ( * overriden ) {
2014-02-10 14:04:30 +08:00
if ( ( existing_fn = zend_hash_find_ptr ( * overriden , key ) ) ! = NULL ) {
2012-12-25 14:23:08 +08:00
if ( existing_fn - > common . fn_flags & ZEND_ACC_ABSTRACT ) {
2012-12-25 20:21:25 +08:00
/* Make sure the trait method is compatible with previosly declared abstract method */
2012-12-25 14:23:08 +08:00
if ( ! zend_traits_method_compatibility_check ( fn , existing_fn TSRMLS_CC ) ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Declaration of %s must be compatible with %s " ,
2012-12-25 14:23:08 +08:00
zend_get_function_declaration ( fn TSRMLS_CC ) ,
zend_get_function_declaration ( existing_fn TSRMLS_CC ) ) ;
}
} else if ( fn - > common . fn_flags & ZEND_ACC_ABSTRACT ) {
/* Make sure the abstract declaration is compatible with previous declaration */
if ( ! zend_traits_method_compatibility_check ( existing_fn , fn TSRMLS_CC ) ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Declaration of %s must be compatible with %s " ,
2012-12-25 14:23:08 +08:00
zend_get_function_declaration ( fn TSRMLS_CC ) ,
zend_get_function_declaration ( existing_fn TSRMLS_CC ) ) ;
}
return ;
}
}
} else {
ALLOC_HASHTABLE ( * overriden ) ;
2014-04-21 22:25:34 +08:00
zend_hash_init_ex ( * overriden , 8 , NULL , ptr_dtor , 0 , 0 ) ;
2011-08-15 19:16:18 +08:00
}
2014-02-10 14:04:30 +08:00
fn = zend_hash_update_mem ( * overriden , key , fn , sizeof ( zend_function ) ) ;
2012-12-25 14:23:08 +08:00
return ;
} else if ( existing_fn - > common . fn_flags & ZEND_ACC_ABSTRACT ) {
2012-12-25 20:21:25 +08:00
/* Make sure the trait method is compatible with previosly declared abstract method */
2012-12-25 14:23:08 +08:00
if ( ! zend_traits_method_compatibility_check ( fn , existing_fn TSRMLS_CC ) ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Declaration of %s must be compatible with %s " ,
2012-12-25 14:23:08 +08:00
zend_get_function_declaration ( fn TSRMLS_CC ) ,
zend_get_function_declaration ( existing_fn TSRMLS_CC ) ) ;
}
} else if ( fn - > common . fn_flags & ZEND_ACC_ABSTRACT ) {
/* Make sure the abstract declaration is compatible with previous declaration */
if ( ! zend_traits_method_compatibility_check ( existing_fn , fn TSRMLS_CC ) ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Declaration of %s must be compatible with %s " ,
2012-12-25 14:23:08 +08:00
zend_get_function_declaration ( fn TSRMLS_CC ) ,
zend_get_function_declaration ( existing_fn TSRMLS_CC ) ) ;
}
return ;
} else if ( ( existing_fn - > common . scope - > ce_flags & ZEND_ACC_TRAIT ) = = ZEND_ACC_TRAIT ) {
2013-10-20 05:22:20 +08:00
/* two traits can't define the same non-abstract method */
2012-12-25 14:23:08 +08:00
# if 1
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Trait method %s has not been applied, because there are collisions with other trait methods on %s " ,
2014-02-21 21:27:53 +08:00
name , ce - > name - > val ) ;
2013-10-20 05:22:20 +08:00
# else /* TODO: better error message */
zend_error_noreturn ( E_COMPILE_ERROR , " Trait method %s::%s has not been applied as %s::%s, because of collision with %s::%s " ,
2014-02-21 21:27:53 +08:00
fn - > common . scope - > name - > val , fn - > common . function_name - > val ,
ce - > name - > val , name ,
existing_fn - > common . scope - > name - > val , existing_fn - > common . function_name - > val ) ;
2012-12-25 14:23:08 +08:00
# endif
} else {
/* inherited members are overridden by members inserted by traits */
2013-06-11 05:20:18 +08:00
/* check whether the trait method fulfills the inheritance requirements */
2011-11-01 23:25:24 +08:00
do_inheritance_check_on_method ( fn , existing_fn TSRMLS_CC ) ;
}
2012-12-25 14:23:08 +08:00
}
2011-11-01 23:25:24 +08:00
2012-12-25 14:23:08 +08:00
function_add_ref ( fn ) ;
2014-02-10 14:04:30 +08:00
fn = zend_hash_update_mem ( & ce - > function_table , key , fn , sizeof ( zend_function ) ) ;
zend_add_magic_methods ( ce , key , fn TSRMLS_CC ) ;
2012-12-25 14:23:08 +08:00
}
/* }}} */
2011-11-01 23:25:24 +08:00
2014-06-17 01:11:52 +08:00
static void zend_fixup_trait_method ( zend_function * fn , zend_class_entry * ce ) /* { { { */
2012-12-25 14:23:08 +08:00
{
if ( ( fn - > common . scope - > ce_flags & ZEND_ACC_TRAIT ) = = ZEND_ACC_TRAIT ) {
fn - > common . scope = ce ;
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
if ( fn - > common . fn_flags & ZEND_ACC_ABSTRACT ) {
ce - > ce_flags | = ZEND_ACC_IMPLICIT_ABSTRACT_CLASS ;
}
2010-07-06 19:40:17 +08:00
if ( fn - > op_array . static_variables ) {
ce - > ce_flags | = ZEND_HAS_STATIC_IN_METHODS ;
}
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
}
}
2011-07-09 03:52:21 +08:00
/* }}} */
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
2014-06-17 01:11:52 +08:00
static int zend_traits_copy_functions ( zend_string * fnname , zend_function * fn , zend_class_entry * ce , HashTable * * overriden , HashTable * exclude_table TSRMLS_DC ) /* { { { */
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
{
2012-12-25 14:23:08 +08:00
zend_trait_alias * alias , * * alias_ptr ;
2014-02-10 14:04:30 +08:00
zend_string * lcname ;
2012-12-25 14:23:08 +08:00
zend_function fn_copy ;
2010-11-19 01:59:04 +08:00
/* apply aliases which are qualified with a class name, there should not be any ambiguity */
2012-12-25 14:23:08 +08:00
if ( ce - > trait_aliases ) {
alias_ptr = ce - > trait_aliases ;
alias = * alias_ptr ;
while ( alias ) {
2011-07-09 03:52:21 +08:00
/* Scope unset or equal to the function we compare to, and the alias applies to fn */
2012-12-25 14:23:08 +08:00
if ( alias - > alias ! = NULL
& & ( ! alias - > trait_method - > ce | | fn - > common . scope = = alias - > trait_method - > ce )
2014-06-17 01:11:52 +08:00
& & alias - > trait_method - > method_name - > len = = fnname - > len
& & ( zend_binary_strcasecmp ( alias - > trait_method - > method_name - > val , alias - > trait_method - > method_name - > len , fnname - > val , fnname - > len ) = = 0 ) ) {
2011-07-09 20:06:11 +08:00
fn_copy = * fn ;
2013-01-28 10:02:51 +08:00
2011-07-09 20:06:11 +08:00
/* if it is 0, no modifieres has been changed */
2013-01-28 10:02:51 +08:00
if ( alias - > modifiers ) {
2012-12-25 14:23:08 +08:00
fn_copy . common . fn_flags = alias - > modifiers | ( fn - > common . fn_flags ^ ( fn - > common . fn_flags & ZEND_ACC_PPP_MASK ) ) ;
2011-07-09 20:06:11 +08:00
}
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
2014-02-10 14:04:30 +08:00
lcname = STR_ALLOC ( alias - > alias - > len , 0 ) ;
zend_str_tolower_copy ( lcname - > val , alias - > alias - > val , alias - > alias - > len ) ;
zend_add_trait_method ( ce , alias - > alias - > val , lcname , & fn_copy , overriden TSRMLS_CC ) ;
2014-02-19 05:12:05 +08:00
STR_RELEASE ( lcname ) ;
2011-11-18 05:04:15 +08:00
2012-12-25 14:23:08 +08:00
/* Record the trait from which this alias was resolved. */
if ( ! alias - > trait_method - > ce ) {
alias - > trait_method - > ce = fn - > common . scope ;
2011-11-18 05:04:15 +08:00
}
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
}
2012-12-25 14:23:08 +08:00
alias_ptr + + ;
alias = * alias_ptr ;
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
}
}
2014-06-17 01:11:52 +08:00
if ( exclude_table = = NULL | | zend_hash_find ( exclude_table , fnname ) = = NULL ) {
2010-04-23 07:16:15 +08:00
/* is not in hashtable, thus, function is not to be excluded */
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
fn_copy = * fn ;
2012-12-25 14:23:08 +08:00
/* apply aliases which have not alias name, just setting visibility */
if ( ce - > trait_aliases ) {
alias_ptr = ce - > trait_aliases ;
alias = * alias_ptr ;
while ( alias ) {
2011-07-09 03:52:21 +08:00
/* Scope unset or equal to the function we compare to, and the alias applies to fn */
2012-12-25 14:23:08 +08:00
if ( alias - > alias = = NULL & & alias - > modifiers ! = 0
& & ( ! alias - > trait_method - > ce | | fn - > common . scope = = alias - > trait_method - > ce )
2014-06-17 01:11:52 +08:00
& & ( alias - > trait_method - > method_name - > len = = fnname - > len )
& & ( zend_binary_strcasecmp ( alias - > trait_method - > method_name - > val , alias - > trait_method - > method_name - > len , fnname - > val , fnname - > len ) = = 0 ) ) {
2012-12-25 14:23:08 +08:00
fn_copy . common . fn_flags = alias - > modifiers | ( fn - > common . fn_flags ^ ( fn - > common . fn_flags & ZEND_ACC_PPP_MASK ) ) ;
2011-11-18 05:04:15 +08:00
/** Record the trait from which this alias was resolved. */
2012-12-25 14:23:08 +08:00
if ( ! alias - > trait_method - > ce ) {
alias - > trait_method - > ce = fn - > common . scope ;
2011-11-18 05:04:15 +08:00
}
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
}
2012-12-25 14:23:08 +08:00
alias_ptr + + ;
alias = * alias_ptr ;
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
}
}
2014-06-17 01:11:52 +08:00
zend_add_trait_method ( ce , fn - > common . function_name - > val , fnname , & fn_copy , overriden TSRMLS_CC ) ;
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
}
return ZEND_HASH_APPLY_KEEP ;
}
2011-07-09 03:52:21 +08:00
/* }}} */
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
2012-12-25 14:23:08 +08:00
static void zend_check_trait_usage ( zend_class_entry * ce , zend_class_entry * trait TSRMLS_DC ) /* { { { */
2011-07-09 03:52:21 +08:00
{
2012-12-25 14:23:08 +08:00
zend_uint i ;
2013-02-21 18:18:41 +08:00
if ( ( trait - > ce_flags & ZEND_ACC_TRAIT ) ! = ZEND_ACC_TRAIT ) {
2014-02-25 05:18:06 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Class %s is not a trait, Only traits may be used in 'as' and 'insteadof' statements " , trait - > name - > val ) ;
2013-02-21 18:18:41 +08:00
}
2012-12-25 14:23:08 +08:00
for ( i = 0 ; i < ce - > num_traits ; i + + ) {
if ( ce - > traits [ i ] = = trait ) {
return ;
}
}
2014-02-21 22:23:56 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Required Trait %s wasn't added to %s " , trait - > name - > val , ce - > 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
}
2011-07-09 03:52:21 +08:00
/* }}} */
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
2010-05-04 06:08:09 +08:00
static void zend_traits_init_trait_structures ( zend_class_entry * ce TSRMLS_DC ) /* { { { */
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
{
size_t i , j = 0 ;
zend_trait_precedence * cur_precedence ;
zend_trait_method_reference * cur_method_ref ;
2014-02-10 14:04:30 +08:00
zend_string * lcname ;
2011-11-18 05:07:52 +08:00
zend_bool method_exists ;
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
2010-04-23 07:16:15 +08:00
/* resolve class references */
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
if ( ce - > trait_precedences ) {
i = 0 ;
while ( ( cur_precedence = ce - > trait_precedences [ i ] ) ) {
2011-11-18 05:04:15 +08:00
/** Resolve classes for all precedence operations. */
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
if ( cur_precedence - > exclude_from_classes ) {
2011-11-18 05:04:15 +08:00
cur_method_ref = cur_precedence - > trait_method ;
2014-02-10 14:04:30 +08:00
if ( ! ( cur_precedence - > trait_method - > ce = zend_fetch_class ( cur_method_ref - > class_name ,
2012-10-08 22:59:52 +08:00
ZEND_FETCH_CLASS_TRAIT | ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC ) ) ) {
2014-05-06 12:45:33 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Could not find trait %s " , cur_method_ref - > class_name - > val ) ;
2012-10-08 22:59:52 +08:00
}
2012-12-25 14:23:08 +08:00
zend_check_trait_usage ( ce , cur_precedence - > trait_method - > ce TSRMLS_CC ) ;
2011-11-18 05:04:15 +08:00
/** Ensure that the prefered method is actually available. */
2014-02-10 14:04:30 +08:00
lcname = STR_ALLOC ( cur_method_ref - > method_name - > len , 0 ) ;
zend_str_tolower_copy ( lcname - > val ,
cur_method_ref - > method_name - > val ,
cur_method_ref - > method_name - > len ) ;
2011-11-18 05:04:15 +08:00
method_exists = zend_hash_exists ( & cur_method_ref - > ce - > function_table ,
2014-02-10 14:04:30 +08:00
lcname ) ;
STR_FREE ( lcname ) ;
2011-11-18 05:04:15 +08:00
if ( ! method_exists ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR ,
2011-11-18 05:04:15 +08:00
" A precedence rule was defined for %s::%s but this method does not exist " ,
2014-02-10 14:04:30 +08:00
cur_method_ref - > ce - > name - > val ,
cur_method_ref - > method_name - > val ) ;
2011-11-18 05:04:15 +08:00
}
2013-01-28 10:02:51 +08:00
2011-11-18 05:04:15 +08:00
/** With the other traits, we are more permissive.
We do not give errors for those . This allows to be more
2012-03-05 03:34:19 +08:00
defensive in such definitions .
2013-07-13 20:37:04 +08:00
However , we want to make sure that the insteadof declaration
2012-03-05 03:34:19 +08:00
is consistent in itself .
*/
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
j = 0 ;
2014-02-10 14:04:30 +08:00
while ( cur_precedence - > exclude_from_classes [ j ] . class_name ) {
zend_string * class_name = cur_precedence - > exclude_from_classes [ j ] . class_name ;
2010-05-03 02:47:27 +08:00
2014-02-10 14:04:30 +08:00
if ( ! ( cur_precedence - > exclude_from_classes [ j ] . ce = zend_fetch_class ( class_name , ZEND_FETCH_CLASS_TRAIT | ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC ) ) ) {
2014-02-25 05:18:06 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Could not find trait %s " , class_name - > val ) ;
2013-01-28 10:02:51 +08:00
}
2014-02-10 14:04:30 +08:00
zend_check_trait_usage ( ce , cur_precedence - > exclude_from_classes [ j ] . ce TSRMLS_CC ) ;
2012-12-25 14:23:08 +08:00
2012-03-05 03:34:19 +08:00
/* make sure that the trait method is not from a class mentioned in
exclude_from_classes , for consistency */
2014-02-10 14:04:30 +08:00
if ( cur_precedence - > trait_method - > ce = = cur_precedence - > exclude_from_classes [ i ] . ce ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR ,
2013-01-28 10:02:51 +08:00
" Inconsistent insteadof definition. "
2012-03-05 03:34:19 +08:00
" The method %s is to be used from %s, but %s is also on the exclude list " ,
2014-02-10 14:04:30 +08:00
cur_method_ref - > method_name - > val ,
cur_precedence - > trait_method - > ce - > name - > val ,
cur_precedence - > trait_method - > ce - > name - > val ) ;
2012-03-05 03:34:19 +08:00
}
2013-01-28 10:02:51 +08:00
2014-02-25 05:18:06 +08:00
STR_RELEASE ( class_name ) ;
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
j + + ;
}
}
i + + ;
}
}
if ( ce - > trait_aliases ) {
i = 0 ;
while ( ce - > trait_aliases [ i ] ) {
2011-11-18 05:04:15 +08:00
/** For all aliases with an explicit class name, resolve the class now. */
2011-07-09 20:06:11 +08:00
if ( ce - > trait_aliases [ i ] - > trait_method - > class_name ) {
cur_method_ref = ce - > trait_aliases [ i ] - > trait_method ;
2014-02-10 14:04:30 +08:00
if ( ! ( cur_method_ref - > ce = zend_fetch_class ( cur_method_ref - > class_name , ZEND_FETCH_CLASS_TRAIT | ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC ) ) ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Could not find trait %s " , cur_method_ref - > class_name - > val ) ;
2012-10-08 22:59:52 +08:00
}
2012-12-25 14:23:08 +08:00
zend_check_trait_usage ( ce , cur_method_ref - > ce TSRMLS_CC ) ;
2011-11-18 05:04:15 +08:00
/** And, ensure that the referenced method is resolvable, too. */
2014-02-10 14:04:30 +08:00
lcname = STR_ALLOC ( cur_method_ref - > method_name - > len , 0 ) ;
zend_str_tolower_copy ( lcname - > val ,
cur_method_ref - > method_name - > val ,
cur_method_ref - > method_name - > len ) ;
2011-11-18 05:04:15 +08:00
method_exists = zend_hash_exists ( & cur_method_ref - > ce - > function_table ,
2014-02-10 14:04:30 +08:00
lcname ) ;
STR_FREE ( lcname ) ;
2011-11-18 05:04:15 +08:00
if ( ! method_exists ) {
2014-02-25 05:18:06 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " An alias was defined for %s::%s but this method does not exist " , cur_method_ref - > ce - > name - > val , cur_method_ref - > method_name - > val ) ;
2011-11-18 05:04:15 +08:00
}
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
}
i + + ;
}
}
}
/* }}} */
2011-07-09 03:52:21 +08:00
static void zend_traits_compile_exclude_table ( HashTable * exclude_table , zend_trait_precedence * * precedences , zend_class_entry * trait ) /* { { { */
{
2011-06-20 09:36:23 +08:00
size_t i = 0 , j ;
2013-01-28 10:02:51 +08:00
2011-06-20 09:36:23 +08:00
if ( ! precedences ) {
return ;
}
while ( precedences [ i ] ) {
if ( precedences [ i ] - > exclude_from_classes ) {
j = 0 ;
2014-02-10 14:04:30 +08:00
while ( precedences [ i ] - > exclude_from_classes [ j ] . ce ) {
if ( precedences [ i ] - > exclude_from_classes [ j ] . ce = = trait ) {
zend_string * lcname = STR_ALLOC ( precedences [ i ] - > trait_method - > method_name - > len , 0 ) ;
zend_str_tolower_copy ( lcname - > val ,
precedences [ i ] - > trait_method - > method_name - > val ,
precedences [ i ] - > trait_method - > method_name - > len ) ;
if ( zend_hash_add_empty_element ( exclude_table , lcname ) = = NULL ) {
STR_RELEASE ( lcname ) ;
2014-02-25 05:18:06 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Failed to evaluate a trait precedence (%s). Method of trait %s was defined to be excluded multiple times " , precedences [ i ] - > trait_method - > method_name - > val , trait - > 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
}
2014-02-10 14:04:30 +08:00
STR_RELEASE ( lcname ) ;
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
}
2011-06-20 09:36:23 +08:00
+ + j ;
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
}
}
2011-06-20 09:36:23 +08:00
+ + i ;
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
}
}
2011-07-09 03:52:21 +08:00
/* }}} */
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
2010-12-20 08:52:40 +08:00
static void zend_do_traits_method_binding ( zend_class_entry * ce TSRMLS_DC ) /* { { { */
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
{
2012-12-25 14:23:08 +08:00
zend_uint i ;
HashTable * overriden = NULL ;
2014-06-17 01:11:52 +08:00
zend_string * key ;
zend_function * fn ;
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
for ( i = 0 ; i < ce - > num_traits ; i + + ) {
2011-07-09 20:06:11 +08:00
if ( ce - > trait_precedences ) {
2012-12-25 14:23:08 +08:00
HashTable exclude_table ;
2011-07-09 20:06:11 +08:00
/* TODO: revisit this start size, may be its not optimal */
2014-04-21 22:25:34 +08:00
zend_hash_init_ex ( & exclude_table , 8 , NULL , NULL , 0 , 0 ) ;
2011-01-20 01:17:52 +08:00
2011-07-09 20:06:11 +08:00
zend_traits_compile_exclude_table ( & exclude_table , ce - > trait_precedences , ce - > traits [ i ] ) ;
/* copies functions, applies defined aliasing, and excludes unused trait methods */
2014-06-17 01:11:52 +08:00
ZEND_HASH_FOREACH_STR_KEY_PTR ( & ce - > traits [ i ] - > function_table , key , fn ) {
zend_traits_copy_functions ( key , fn , ce , & overriden , & exclude_table TSRMLS_CC ) ;
} ZEND_HASH_FOREACH_END ( ) ;
2012-12-25 14:23:08 +08:00
2012-01-20 20:30:57 +08:00
zend_hash_destroy ( & exclude_table ) ;
2011-07-09 20:06:11 +08:00
} else {
2014-06-17 01:11:52 +08:00
ZEND_HASH_FOREACH_STR_KEY_PTR ( & ce - > traits [ i ] - > function_table , key , fn ) {
zend_traits_copy_functions ( key , fn , ce , & overriden , NULL TSRMLS_CC ) ;
} ZEND_HASH_FOREACH_END ( ) ;
2011-07-09 20:06:11 +08:00
}
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
}
2013-01-28 10:02:51 +08:00
2014-06-17 01:11:52 +08:00
ZEND_HASH_FOREACH_PTR ( & ce - > function_table , fn ) {
zend_fixup_trait_method ( fn , ce ) ;
} ZEND_HASH_FOREACH_END ( ) ;
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
2012-12-25 14:23:08 +08:00
if ( overriden ) {
zend_hash_destroy ( overriden ) ;
FREE_HASHTABLE ( overriden ) ;
}
2010-12-20 08:52:40 +08:00
}
2011-10-04 01:01:17 +08:00
/* }}} */
2010-12-20 08:52:40 +08:00
2014-02-10 14:04:30 +08:00
static zend_class_entry * find_first_definition ( zend_class_entry * ce , size_t current_trait , zend_string * prop_name , zend_class_entry * coliding_ce ) /* { { { */
2010-12-20 08:52:40 +08:00
{
size_t i ;
2012-12-25 14:23:08 +08:00
if ( coliding_ce = = ce ) {
for ( i = 0 ; i < current_trait ; i + + ) {
2014-02-10 14:04:30 +08:00
if ( zend_hash_exists ( & ce - > traits [ i ] - > properties_info , prop_name ) ) {
2012-12-25 14:23:08 +08:00
return ce - > traits [ i ] ;
}
2011-12-20 00:48:18 +08:00
}
2012-01-20 20:30:57 +08:00
}
2012-12-25 14:23:08 +08:00
return coliding_ce ;
2011-12-20 00:48:18 +08:00
}
/* }}} */
2010-12-20 08:52:40 +08:00
static void zend_do_traits_property_binding ( zend_class_entry * ce TSRMLS_DC ) /* { { { */
{
size_t i ;
zend_property_info * property_info ;
zend_property_info * coliding_prop ;
zval compare_result ;
2014-02-10 14:04:30 +08:00
zend_string * prop_name ;
2011-09-13 21:29:35 +08:00
const char * class_name_unused ;
2010-12-20 09:42:25 +08:00
zend_bool not_compatible ;
2010-12-20 08:52:40 +08:00
zval * prop_value ;
2012-12-25 14:23:08 +08:00
zend_uint flags ;
2014-02-25 05:18:06 +08:00
zend_string * doc_comment ;
2012-12-25 14:23:08 +08:00
2011-07-09 03:52:21 +08:00
/* In the following steps the properties are inserted into the property table
* for that , a very strict approach is applied :
* - check for compatibility , if not compatible with any property in class - > fatal
* - if compatible , then strict notice
*/
2010-12-20 08:52:40 +08:00
for ( i = 0 ; i < ce - > num_traits ; i + + ) {
2014-04-18 23:18:11 +08:00
ZEND_HASH_FOREACH_PTR ( & ce - > traits [ i ] - > properties_info , property_info ) {
2010-12-20 08:52:40 +08:00
/* first get the unmangeld name if necessary,
2011-07-09 03:52:21 +08:00
* then check whether the property is already there
*/
2012-12-25 14:23:08 +08:00
flags = property_info - > flags ;
if ( ( flags & ZEND_ACC_PPP_MASK ) = = ZEND_ACC_PUBLIC ) {
2014-02-25 05:18:06 +08:00
prop_name = STR_COPY ( property_info - > name ) ;
2010-12-20 09:42:25 +08:00
} else {
2014-02-10 14:04:30 +08:00
const char * pname ;
int pname_len ;
2010-12-20 08:52:40 +08:00
/* for private and protected we need to unmangle the names */
2014-02-10 14:04:30 +08:00
zend_unmangle_property_name_ex ( property_info - > name - > val , property_info - > name - > len ,
& class_name_unused , & pname , & pname_len ) ;
prop_name = STR_INIT ( pname , pname_len , 0 ) ;
2010-12-20 08:52:40 +08:00
}
2011-01-20 01:17:52 +08:00
2010-12-20 08:52:40 +08:00
/* next: check for conflicts with current class */
2014-02-10 14:04:30 +08:00
if ( ( coliding_prop = zend_hash_find_ptr ( & ce - > properties_info , prop_name ) ) ! = NULL ) {
2013-01-28 10:02:51 +08:00
if ( coliding_prop - > flags & ZEND_ACC_SHADOW ) {
2014-02-10 14:04:30 +08:00
zend_hash_del ( & ce - > properties_info , prop_name ) ;
2012-12-25 14:23:08 +08:00
flags | = ZEND_ACC_CHANGED ;
2013-01-28 10:02:51 +08:00
} else {
2012-12-25 14:23:08 +08:00
if ( ( coliding_prop - > flags & ( ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC ) )
= = ( flags & ( ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC ) ) ) {
/* flags are identical, now the value needs to be checked */
if ( flags & ZEND_ACC_STATIC ) {
not_compatible = ( FAILURE = = compare_function ( & compare_result ,
2014-02-10 14:04:30 +08:00
& ce - > default_static_members_table [ coliding_prop - > offset ] ,
& ce - > traits [ i ] - > default_static_members_table [ property_info - > offset ] TSRMLS_CC ) )
2012-12-25 14:23:08 +08:00
| | ( Z_LVAL ( compare_result ) ! = 0 ) ;
2011-12-17 22:26:39 +08:00
} else {
2012-12-25 14:23:08 +08:00
not_compatible = ( FAILURE = = compare_function ( & compare_result ,
2014-02-10 14:04:30 +08:00
& ce - > default_properties_table [ coliding_prop - > offset ] ,
& ce - > traits [ i ] - > default_properties_table [ property_info - > offset ] TSRMLS_CC ) )
2012-12-25 14:23:08 +08:00
| | ( Z_LVAL ( compare_result ) ! = 0 ) ;
2011-12-17 22:26:39 +08:00
}
2011-12-20 00:48:18 +08:00
} else {
2012-12-25 14:23:08 +08:00
/* the flags are not identical, thus, we assume properties are not compatible */
not_compatible = 1 ;
2011-12-20 00:48:18 +08:00
}
2012-12-25 14:23:08 +08:00
if ( not_compatible ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR ,
2012-01-20 20:30:57 +08:00
" %s and %s define the same property ($%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed " ,
2014-02-10 14:04:30 +08:00
find_first_definition ( ce , i , prop_name , coliding_prop - > ce ) - > name - > val ,
property_info - > ce - > name - > val ,
prop_name - > val ,
ce - > name - > val ) ;
2012-12-25 14:23:08 +08:00
} else {
2013-01-28 10:02:51 +08:00
zend_error ( E_STRICT ,
2012-01-20 20:30:57 +08:00
" %s and %s define the same property ($%s) in the composition of %s. This might be incompatible, to improve maintainability consider using accessor methods in traits instead. Class was composed " ,
2014-02-10 14:04:30 +08:00
find_first_definition ( ce , i , prop_name , coliding_prop - > ce ) - > name - > val ,
property_info - > ce - > name - > val ,
prop_name - > val ,
ce - > name - > val ) ;
2014-02-25 05:18:06 +08:00
STR_RELEASE ( prop_name ) ;
2012-12-25 14:23:08 +08:00
continue ;
}
2010-12-20 08:52:40 +08:00
}
}
2011-01-20 01:17:52 +08:00
2010-12-20 08:52:40 +08:00
/* property not found, so lets add it */
2012-12-25 14:23:08 +08:00
if ( flags & ZEND_ACC_STATIC ) {
2014-02-10 14:04:30 +08:00
prop_value = & ce - > traits [ i ] - > default_static_members_table [ property_info - > offset ] ;
2010-12-20 09:42:25 +08:00
} else {
2014-02-10 14:04:30 +08:00
prop_value = & ce - > traits [ i ] - > default_properties_table [ property_info - > offset ] ;
2010-12-20 08:52:40 +08:00
}
2014-02-22 00:35:40 +08:00
if ( Z_REFCOUNTED_P ( prop_value ) ) Z_ADDREF_P ( prop_value ) ;
2010-12-20 08:52:40 +08:00
2014-02-25 05:18:06 +08:00
doc_comment = property_info - > doc_comment ? STR_COPY ( property_info - > doc_comment ) : NULL ;
2014-02-10 14:04:30 +08:00
zend_declare_property_ex ( ce , prop_name ,
2013-01-28 10:02:51 +08:00
prop_value , flags ,
2014-02-25 05:18:06 +08:00
doc_comment TSRMLS_CC ) ;
STR_RELEASE ( prop_name ) ;
2014-04-18 23:18:11 +08:00
} ZEND_HASH_FOREACH_END ( ) ;
2010-12-20 08:52:40 +08:00
}
}
2011-07-09 03:52:21 +08:00
/* }}} */
2010-12-20 08:52:40 +08:00
2011-11-18 05:04:15 +08:00
static void zend_do_check_for_inconsistent_traits_aliasing ( zend_class_entry * ce TSRMLS_DC ) /* { { { */
{
int i = 0 ;
2011-11-18 21:49:07 +08:00
zend_trait_alias * cur_alias ;
2014-02-10 14:04:30 +08:00
zend_string * lc_method_name ;
2013-01-28 10:02:51 +08:00
2011-11-18 05:04:15 +08:00
if ( ce - > trait_aliases ) {
while ( ce - > trait_aliases [ i ] ) {
2011-11-18 21:49:07 +08:00
cur_alias = ce - > trait_aliases [ i ] ;
2011-11-18 05:04:15 +08:00
/** The trait for this alias has not been resolved, this means, this
alias was not applied . Abort with an error . */
2011-11-18 21:49:07 +08:00
if ( ! cur_alias - > trait_method - > ce ) {
if ( cur_alias - > alias ) {
/** Plain old inconsistency/typo/bug */
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR ,
2011-11-18 21:49:07 +08:00
" An alias (%s) was defined for method %s(), but this method does not exist " ,
2014-02-25 05:18:06 +08:00
cur_alias - > alias - > val ,
cur_alias - > trait_method - > method_name - > val ) ;
2011-11-18 21:56:41 +08:00
} else {
2011-11-18 21:49:07 +08:00
/** Here are two possible cases:
1 ) this is an attempt to modifiy the visibility
of a method introduce as part of another alias .
Since that seems to violate the DRY principle ,
we check against it and abort .
2 ) it is just a plain old inconsitency / typo / bug
as in the case where alias is set . */
2013-01-28 10:02:51 +08:00
2014-02-10 14:04:30 +08:00
lc_method_name = STR_ALLOC ( cur_alias - > trait_method - > method_name - > len , 0 ) ;
zend_str_tolower_copy (
lc_method_name - > val ,
cur_alias - > trait_method - > method_name - > val ,
cur_alias - > trait_method - > method_name - > len ) ;
2011-11-18 21:49:07 +08:00
if ( zend_hash_exists ( & ce - > function_table ,
2014-02-10 14:04:30 +08:00
lc_method_name ) ) {
STR_FREE ( lc_method_name ) ;
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR ,
2011-11-18 21:49:07 +08:00
" The modifiers for the trait alias %s() need to be changed in the same statment in which the alias is defined. Error " ,
2014-02-10 14:04:30 +08:00
cur_alias - > trait_method - > method_name - > val ) ;
2011-11-18 21:56:41 +08:00
} else {
2014-02-10 14:04:30 +08:00
STR_FREE ( lc_method_name ) ;
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR ,
2011-11-18 21:49:07 +08:00
" The modifiers of the trait method %s() are changed, but this method does not exist. Error " ,
2014-02-10 14:04:30 +08:00
cur_alias - > trait_method - > method_name - > val ) ;
2011-11-18 21:49:07 +08:00
}
}
2011-11-18 05:04:15 +08:00
}
i + + ;
}
}
}
/* }}} */
2010-12-20 08:52:40 +08:00
ZEND_API void zend_do_bind_traits ( zend_class_entry * ce TSRMLS_DC ) /* { { { */
{
if ( ce - > num_traits < = 0 ) {
return ;
}
/* complete initialization of trait strutures in ce */
zend_traits_init_trait_structures ( ce TSRMLS_CC ) ;
/* first care about all methods to be flattened into the class */
zend_do_traits_method_binding ( ce TSRMLS_CC ) ;
2013-01-28 10:02:51 +08:00
2011-11-18 05:04:15 +08:00
/* Aliases which have not been applied indicate typos/bugs. */
zend_do_check_for_inconsistent_traits_aliasing ( ce TSRMLS_CC ) ;
2010-12-20 08:52:40 +08:00
/* then flatten the properties into it, to, mostly to notfiy developer about problems */
zend_do_traits_property_binding ( ce TSRMLS_CC ) ;
/* verify that all abstract methods from traits have been implemented */
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
zend_verify_abstract_class ( ce TSRMLS_CC ) ;
2013-01-28 10:02:51 +08:00
2010-04-23 07:16:15 +08:00
/* now everything should be fine and an added ZEND_ACC_IMPLICIT_ABSTRACT_CLASS should be removed */
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
if ( ce - > ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS ) {
ce - > ce_flags - = ZEND_ACC_IMPLICIT_ABSTRACT_CLASS ;
}
}
/* }}} */
2010-04-20 18:57:45 +08:00
ZEND_API int do_bind_function ( const zend_op_array * op_array , zend_op * opline , HashTable * function_table , zend_bool compile_time ) /* { { { */
2002-09-25 03:05:53 +08:00
{
2014-02-17 21:59:18 +08:00
zend_function * function , * new_function ;
2010-04-20 18:57:45 +08:00
zval * op1 , * op2 ;
if ( compile_time ) {
op1 = & CONSTANT_EX ( op_array , opline - > op1 . constant ) ;
op2 = & CONSTANT_EX ( op_array , opline - > op2 . constant ) ;
} else {
op1 = opline - > op1 . zv ;
op2 = opline - > op2 . zv ;
}
1999-05-15 23:47:24 +08:00
2014-02-10 14:04:30 +08:00
function = zend_hash_find_ptr ( function_table , Z_STR_P ( op1 ) ) ;
2014-02-17 21:59:18 +08:00
new_function = emalloc ( sizeof ( zend_op_array ) ) ;
memcpy ( new_function , function , sizeof ( zend_op_array ) ) ;
if ( zend_hash_add_ptr ( function_table , Z_STR_P ( op2 ) , new_function ) = = NULL ) {
2003-09-03 16:39:43 +08:00
int error_level = compile_time ? E_COMPILE_ERROR : E_ERROR ;
2009-04-08 21:17:09 +08:00
zend_function * old_function ;
2002-09-25 03:05:53 +08:00
2014-02-17 21:59:18 +08:00
efree ( new_function ) ;
2014-02-10 14:04:30 +08:00
if ( ( old_function = zend_hash_find_ptr ( function_table , Z_STR_P ( op2 ) ) ) ! = NULL
2009-04-08 21:17:09 +08:00
& & old_function - > type = = ZEND_USER_FUNCTION
& & old_function - > op_array . last > 0 ) {
2002-09-25 03:05:53 +08:00
zend_error ( error_level , " Cannot redeclare %s() (previously declared in %s:%d) " ,
2014-02-10 14:04:30 +08:00
function - > common . function_name - > val ,
old_function - > op_array . filename - > val ,
2009-04-08 21:17:09 +08:00
old_function - > op_array . opcodes [ 0 ] . lineno ) ;
2002-09-25 03:05:53 +08:00
} else {
2014-02-10 14:04:30 +08:00
zend_error ( error_level , " Cannot redeclare %s() " , function - > common . function_name - > val ) ;
2002-09-25 03:05:53 +08:00
}
return FAILURE ;
} else {
2014-02-26 03:56:09 +08:00
( * function - > op_array . refcount ) + + ;
function - > op_array . static_variables = NULL ; /* NULL out the unbound function */
2002-09-25 03:05:53 +08:00
return SUCCESS ;
}
}
2009-07-27 22:11:53 +08:00
/* }}} */
2006-05-10 07:53:23 +08:00
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
void zend_prepare_reference ( znode * result , znode * class_name , znode * method_name TSRMLS_DC ) /* { { { */
{
zend_trait_method_reference * method_ref = emalloc ( sizeof ( zend_trait_method_reference ) ) ;
method_ref - > ce = NULL ;
2013-01-28 10:02:51 +08:00
/* REM: There should not be a need for copying,
2010-04-23 07:16:15 +08:00
zend_do_begin_class_declaration is also just using that string */
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
if ( class_name ) {
2013-09-13 18:18:39 +08:00
zend_resolve_class_name ( class_name TSRMLS_CC ) ;
2014-02-10 14:04:30 +08:00
method_ref - > class_name = Z_STR ( class_name - > u . constant ) ;
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 {
method_ref - > class_name = NULL ;
}
2014-02-10 14:04:30 +08:00
method_ref - > method_name = Z_STR ( method_name - > u . constant ) ;
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
result - > u . op . ptr = method_ref ;
2010-05-03 02:47:27 +08:00
result - > op_type = IS_TMP_VAR ;
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
}
/* }}} */
2012-12-25 14:23:08 +08:00
void zend_add_trait_alias ( znode * method_reference , znode * modifiers , znode * alias TSRMLS_DC ) /* { { { */
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
{
2012-12-25 14:23:08 +08:00
zend_class_entry * ce = CG ( active_class_entry ) ;
zend_trait_alias * trait_alias ;
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
2010-05-07 03:20:12 +08:00
if ( Z_LVAL ( modifiers - > u . constant ) = = ZEND_ACC_STATIC ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use 'static' as method modifier " ) ;
2010-05-07 03:20:12 +08:00
return ;
2012-12-25 14:23:08 +08:00
} else if ( Z_LVAL ( modifiers - > u . constant ) = = ZEND_ACC_ABSTRACT ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use 'abstract' as method modifier " ) ;
2012-12-25 14:23:08 +08:00
return ;
} else if ( Z_LVAL ( modifiers - > u . constant ) = = ZEND_ACC_FINAL ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use 'final' as method modifier " ) ;
2012-12-25 14:23:08 +08:00
return ;
2010-05-07 03:20:12 +08:00
}
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
2012-12-25 14:23:08 +08:00
trait_alias = emalloc ( sizeof ( zend_trait_alias ) ) ;
trait_alias - > trait_method = ( zend_trait_method_reference * ) method_reference - > u . op . ptr ;
trait_alias - > modifiers = Z_LVAL ( modifiers - > u . constant ) ;
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
if ( alias ) {
2014-02-10 14:04:30 +08:00
trait_alias - > alias = Z_STR ( alias - > u . constant ) ;
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 {
trait_alias - > alias = NULL ;
}
2012-12-25 14:23:08 +08:00
zend_add_to_list ( & ce - > trait_aliases , trait_alias TSRMLS_CC ) ;
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
}
/* }}} */
2012-12-25 14:23:08 +08:00
void zend_add_trait_precedence ( znode * method_reference , znode * trait_list TSRMLS_DC ) /* { { { */
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
{
2012-12-25 14:23:08 +08:00
zend_class_entry * ce = CG ( active_class_entry ) ;
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
zend_trait_precedence * trait_precedence = emalloc ( sizeof ( zend_trait_precedence ) ) ;
trait_precedence - > trait_method = ( zend_trait_method_reference * ) method_reference - > u . op . ptr ;
2014-02-10 14:04:30 +08:00
trait_precedence - > exclude_from_classes = trait_list - > u . op . ptr ;
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
2012-12-25 14:23:08 +08:00
zend_add_to_list ( & ce - > trait_precedences , trait_precedence TSRMLS_CC ) ;
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
}
/* }}} */
2010-04-20 18:57:45 +08:00
ZEND_API zend_class_entry * do_bind_class ( const zend_op_array * op_array , const zend_op * opline , HashTable * class_table , zend_bool compile_time TSRMLS_DC ) /* { { { */
2002-09-25 03:05:53 +08:00
{
2014-02-10 14:04:30 +08:00
zend_class_entry * ce ;
2010-04-20 18:57:45 +08:00
zval * op1 , * op2 ;
2002-09-25 03:05:53 +08:00
2010-04-20 18:57:45 +08:00
if ( compile_time ) {
op1 = & CONSTANT_EX ( op_array , opline - > op1 . constant ) ;
op2 = & CONSTANT_EX ( op_array , opline - > op2 . constant ) ;
} else {
op1 = opline - > op1 . zv ;
op2 = opline - > op2 . zv ;
}
2014-02-10 14:04:30 +08:00
if ( ( ce = zend_hash_find_ptr ( class_table , Z_STR_P ( op1 ) ) ) = = NULL ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Internal Zend error - Missing class information for %s " , Z_STRVAL_P ( op1 ) ) ;
2003-03-05 19:14:44 +08:00
return NULL ;
2002-09-25 03:05:53 +08:00
}
ce - > refcount + + ;
2014-02-10 14:04:30 +08:00
if ( zend_hash_add_ptr ( class_table , Z_STR_P ( op2 ) , ce ) = = NULL ) {
2002-09-25 03:05:53 +08:00
ce - > refcount - - ;
2004-02-05 00:30:15 +08:00
if ( ! compile_time ) {
/* If we're in compile time, in practice, it's quite possible
* that we ' ll never reach this class declaration at runtime ,
* so we shut up about it . This allows the if ( ! defined ( ' FOO ' ) ) { return ; }
* approach to work .
*/
2014-02-10 14:04:30 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot redeclare class %s " , ce - > name - > val ) ;
2004-02-05 00:30:15 +08:00
}
2003-03-05 19:14:44 +08:00
return NULL ;
2002-09-25 03:05:53 +08:00
} else {
2012-12-25 14:23:08 +08:00
if ( ! ( ce - > ce_flags & ( ZEND_ACC_INTERFACE | ZEND_ACC_IMPLEMENT_INTERFACES | ZEND_ACC_IMPLEMENT_TRAITS ) ) ) {
2004-02-05 01:10:44 +08:00
zend_verify_abstract_class ( ce TSRMLS_CC ) ;
}
2003-03-05 19:14:44 +08:00
return ce ;
2002-09-25 03:05:53 +08:00
}
}
2009-07-27 22:11:53 +08:00
/* }}} */
2000-05-26 00:26:22 +08:00
2010-04-20 18:57:45 +08:00
ZEND_API zend_class_entry * do_bind_inherited_class ( const zend_op_array * op_array , const zend_op * opline , HashTable * class_table , zend_class_entry * parent_ce , zend_bool compile_time TSRMLS_DC ) /* { { { */
2002-09-25 03:05:53 +08:00
{
2014-02-10 14:04:30 +08:00
zend_class_entry * ce ;
2010-04-20 18:57:45 +08:00
zval * op1 , * op2 ;
if ( compile_time ) {
op1 = & CONSTANT_EX ( op_array , opline - > op1 . constant ) ;
op2 = & CONSTANT_EX ( op_array , opline - > op2 . constant ) ;
} else {
op1 = opline - > op1 . zv ;
op2 = opline - > op2 . zv ;
}
2002-09-15 15:54:01 +08:00
2014-02-10 14:04:30 +08:00
ce = zend_hash_find_ptr ( class_table , Z_STR_P ( op1 ) ) ;
2002-09-25 03:05:53 +08:00
2014-02-10 14:04:30 +08:00
if ( ! ce ) {
2004-02-05 00:30:15 +08:00
if ( ! compile_time ) {
/* If we're in compile time, in practice, it's quite possible
* that we ' ll never reach this class declaration at runtime ,
* so we shut up about it . This allows the if ( ! defined ( ' FOO ' ) ) { return ; }
* approach to work .
*/
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot redeclare class %s " , Z_STRVAL_P ( op2 ) ) ;
2004-02-05 00:30:15 +08:00
}
2003-03-05 19:14:44 +08:00
return NULL ;
2002-09-25 03:05:53 +08:00
}
2004-08-27 06:59:25 +08:00
if ( parent_ce - > ce_flags & ZEND_ACC_INTERFACE ) {
2014-02-21 22:23:56 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Class %s cannot extend from interface %s " , ce - > name - > val , parent_ce - > name - > val ) ;
2010-05-07 19:09:35 +08:00
} else if ( ( parent_ce - > ce_flags & ZEND_ACC_TRAIT ) = = ZEND_ACC_TRAIT ) {
2014-02-21 22:23:56 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Class %s cannot extend from trait %s " , ce - > name - > val , parent_ce - > name - > val ) ;
2004-08-27 06:59:25 +08:00
}
2003-10-23 03:59:58 +08:00
zend_do_inheritance ( ce , parent_ce TSRMLS_CC ) ;
2002-09-25 03:05:53 +08:00
2002-09-25 03:32:01 +08:00
ce - > refcount + + ;
2002-09-25 03:05:53 +08:00
/* Register the derived class */
2014-02-10 14:04:30 +08:00
if ( zend_hash_add_ptr ( class_table , Z_STR_P ( op2 ) , ce ) = = NULL ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot redeclare class %s " , ce - > name - > val ) ;
2002-09-25 03:05:53 +08:00
}
2003-03-05 19:14:44 +08:00
return ce ;
1999-05-15 23:47:24 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-05-15 23:47:24 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_early_binding ( TSRMLS_D ) /* { { { */
1999-05-15 23:47:24 +08:00
{
zend_op * opline = & CG ( active_op_array ) - > opcodes [ CG ( active_op_array ) - > last - 1 ] ;
2004-02-05 00:30:15 +08:00
HashTable * table ;
1999-05-15 23:47:24 +08:00
2003-01-28 19:34:24 +08:00
while ( opline - > opcode = = ZEND_TICKS & & opline > CG ( active_op_array ) - > opcodes ) {
opline - - ;
}
2004-02-05 00:30:15 +08:00
switch ( opline - > opcode ) {
case ZEND_DECLARE_FUNCTION :
2010-04-20 18:57:45 +08:00
if ( do_bind_function ( CG ( active_op_array ) , opline , CG ( function_table ) , 1 ) = = FAILURE ) {
2004-02-05 00:30:15 +08:00
return ;
}
table = CG ( function_table ) ;
break ;
2004-02-05 01:10:44 +08:00
case ZEND_DECLARE_CLASS :
2010-04-20 18:57:45 +08:00
if ( do_bind_class ( CG ( active_op_array ) , opline , CG ( class_table ) , 1 TSRMLS_CC ) = = NULL ) {
2008-03-18 16:36:30 +08:00
return ;
}
table = CG ( class_table ) ;
break ;
2004-02-05 01:10:44 +08:00
case ZEND_DECLARE_INHERITED_CLASS :
2008-03-18 16:36:30 +08:00
{
zend_op * fetch_class_opline = opline - 1 ;
2010-04-20 18:57:45 +08:00
zval * parent_name ;
2014-02-10 14:04:30 +08:00
zend_class_entry * ce ;
2008-03-18 16:36:30 +08:00
2010-04-20 18:57:45 +08:00
parent_name = & CONSTANT ( fetch_class_opline - > op2 . constant ) ;
2014-02-10 14:04:30 +08:00
if ( ( ( ce = zend_lookup_class ( Z_STR_P ( parent_name ) TSRMLS_CC ) ) = = NULL ) | |
2008-03-18 16:36:30 +08:00
( ( CG ( compiler_options ) & ZEND_COMPILE_IGNORE_INTERNAL_CLASSES ) & &
2014-02-10 14:04:30 +08:00
( ce - > type = = ZEND_INTERNAL_CLASS ) ) ) {
2008-03-18 16:36:30 +08:00
if ( CG ( compiler_options ) & ZEND_COMPILE_DELAYED_BINDING ) {
zend_uint * opline_num = & CG ( active_op_array ) - > early_binding ;
while ( * opline_num ! = - 1 ) {
2010-04-20 18:57:45 +08:00
opline_num = & CG ( active_op_array ) - > opcodes [ * opline_num ] . result . opline_num ;
2008-03-18 16:36:30 +08:00
}
* opline_num = opline - CG ( active_op_array ) - > opcodes ;
opline - > opcode = ZEND_DECLARE_INHERITED_CLASS_DELAYED ;
2010-04-20 18:57:45 +08:00
opline - > result_type = IS_UNUSED ;
opline - > result . opline_num = - 1 ;
2004-02-05 00:30:15 +08:00
}
return ;
}
2014-02-10 14:04:30 +08:00
if ( do_bind_inherited_class ( CG ( active_op_array ) , opline , CG ( class_table ) , ce , 1 TSRMLS_CC ) = = NULL ) {
2008-03-18 16:36:30 +08:00
return ;
2004-02-05 01:10:44 +08:00
}
2008-03-18 16:36:30 +08:00
/* clear unnecessary ZEND_FETCH_CLASS opcode */
2010-04-20 18:57:45 +08:00
zend_del_literal ( CG ( active_op_array ) , fetch_class_opline - > op2 . constant ) ;
2008-03-18 16:36:30 +08:00
MAKE_NOP ( fetch_class_opline ) ;
2004-02-05 00:30:15 +08:00
2008-03-18 16:36:30 +08:00
table = CG ( class_table ) ;
break ;
}
case ZEND_VERIFY_ABSTRACT_CLASS :
2004-02-05 02:24:44 +08:00
case ZEND_ADD_INTERFACE :
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
case ZEND_ADD_TRAIT :
case ZEND_BIND_TRAITS :
2004-02-05 02:24:44 +08:00
/* We currently don't early-bind classes that implement interfaces */
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
/* Classes with traits are handled exactly the same, no early-bind here */
2004-02-05 02:24:44 +08:00
return ;
2004-02-05 00:30:15 +08:00
default :
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Invalid binding type " ) ;
2004-02-05 00:30:15 +08:00
return ;
1999-07-27 05:18:35 +08:00
}
2002-09-25 03:05:53 +08:00
2014-02-10 14:04:30 +08:00
zend_hash_del ( table , Z_STR ( CONSTANT ( opline - > op1 . constant ) ) ) ;
2010-04-20 18:57:45 +08:00
zend_del_literal ( CG ( active_op_array ) , opline - > op1 . constant ) ;
zend_del_literal ( CG ( active_op_array ) , opline - > op2 . constant ) ;
2008-03-18 16:36:30 +08:00
MAKE_NOP ( opline ) ;
1999-05-15 23:47:24 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-05-15 23:47:24 +08:00
2009-07-27 22:11:53 +08:00
ZEND_API void zend_do_delayed_early_binding ( const zend_op_array * op_array TSRMLS_DC ) /* { { { */
2008-03-18 16:36:30 +08:00
{
if ( op_array - > early_binding ! = - 1 ) {
zend_bool orig_in_compilation = CG ( in_compilation ) ;
zend_uint opline_num = op_array - > early_binding ;
2014-02-10 14:04:30 +08:00
zend_class_entry * ce ;
2008-03-18 16:36:30 +08:00
CG ( in_compilation ) = 1 ;
while ( opline_num ! = - 1 ) {
2014-02-10 14:04:30 +08:00
if ( ( ce = zend_lookup_class ( Z_STR_P ( op_array - > opcodes [ opline_num - 1 ] . op2 . zv ) TSRMLS_CC ) ) ! = NULL ) {
do_bind_inherited_class ( op_array , & op_array - > opcodes [ opline_num ] , EG ( class_table ) , ce , 0 TSRMLS_CC ) ;
2008-03-18 16:36:30 +08:00
}
2010-04-20 18:57:45 +08:00
opline_num = op_array - > opcodes [ opline_num ] . result . opline_num ;
2008-03-18 16:36:30 +08:00
}
CG ( in_compilation ) = orig_in_compilation ;
}
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-05-15 23:47:24 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_boolean_or_begin ( znode * expr1 , znode * op_token TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
int next_op_number = get_next_op_number ( CG ( active_op_array ) ) ;
2001-07-28 18:51:54 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
opline - > opcode = ZEND_JMPNZ_EX ;
if ( expr1 - > op_type = = IS_TMP_VAR ) {
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > result , expr1 ) ;
1999-04-08 02:10:10 +08:00
} else {
2010-04-20 18:57:45 +08:00
opline - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
opline - > result_type = IS_TMP_VAR ;
1999-04-08 02:10:10 +08:00
}
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op1 , expr1 ) ;
1999-04-08 02:10:10 +08:00
SET_UNUSED ( opline - > op2 ) ;
2006-05-10 07:53:23 +08:00
2010-04-20 18:57:45 +08:00
op_token - > u . op . opline_num = next_op_number ;
1999-04-08 02:10:10 +08:00
2010-04-20 18:57:45 +08:00
GET_NODE ( expr1 , opline - > result ) ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_boolean_or_end ( znode * result , znode * expr1 , znode * expr2 , const znode * op_token TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2001-07-28 18:51:54 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
* result = * expr1 ; /* we saved the original result in expr1 */
opline - > opcode = ZEND_BOOL ;
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > result , result ) ;
SET_NODE ( opline - > op1 , expr2 ) ;
1999-04-08 02:10:10 +08:00
SET_UNUSED ( opline - > op2 ) ;
2010-04-20 18:57:45 +08:00
CG ( active_op_array ) - > opcodes [ op_token - > u . op . opline_num ] . op2 . opline_num = get_next_op_number ( CG ( active_op_array ) ) ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_boolean_and_begin ( znode * expr1 , znode * op_token TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
int next_op_number = get_next_op_number ( CG ( active_op_array ) ) ;
2001-07-28 18:51:54 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
opline - > opcode = ZEND_JMPZ_EX ;
if ( expr1 - > op_type = = IS_TMP_VAR ) {
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > result , expr1 ) ;
1999-04-08 02:10:10 +08:00
} else {
2010-04-20 18:57:45 +08:00
opline - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
opline - > result_type = IS_TMP_VAR ;
1999-04-08 02:10:10 +08:00
}
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op1 , expr1 ) ;
1999-04-08 02:10:10 +08:00
SET_UNUSED ( opline - > op2 ) ;
2006-05-10 07:53:23 +08:00
2010-04-20 18:57:45 +08:00
op_token - > u . op . opline_num = next_op_number ;
1999-04-08 02:10:10 +08:00
2010-04-20 18:57:45 +08:00
GET_NODE ( expr1 , opline - > result ) ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_boolean_and_end ( znode * result , znode * expr1 , znode * expr2 , const znode * op_token TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2001-07-28 18:51:54 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
* result = * expr1 ; /* we saved the original result in expr1 */
opline - > opcode = ZEND_BOOL ;
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > result , result ) ;
SET_NODE ( opline - > op1 , expr2 ) ;
1999-04-08 02:10:10 +08:00
SET_UNUSED ( opline - > op2 ) ;
2010-04-20 18:57:45 +08:00
CG ( active_op_array ) - > opcodes [ op_token - > u . op . opline_num ] . op2 . opline_num = get_next_op_number ( CG ( active_op_array ) ) ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_do_while_begin ( TSRMLS_D ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2001-07-28 18:51:54 +08:00
do_begin_loop ( TSRMLS_C ) ;
1999-04-08 02:10:10 +08:00
INC_BPC ( CG ( active_op_array ) ) ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_do_while_end ( const znode * do_token , const znode * expr_open_bracket , znode * expr TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2001-07-28 18:51:54 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
opline - > opcode = ZEND_JMPNZ ;
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op1 , expr ) ;
opline - > op2 . opline_num = do_token - > u . op . opline_num ;
1999-06-23 04:24:51 +08:00
SET_UNUSED ( opline - > op2 ) ;
1999-04-08 02:10:10 +08:00
2010-04-20 18:57:45 +08:00
do_end_loop ( expr_open_bracket - > u . op . opline_num , 0 TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
DEC_BPC ( CG ( active_op_array ) ) ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_brk_cont ( zend_uchar op , znode * expr TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2001-07-28 18:51:54 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
opline - > opcode = op ;
2010-09-15 15:38:52 +08:00
opline - > op1 . opline_num = CG ( context ) . current_brk_cont ;
1999-04-08 02:10:10 +08:00
SET_UNUSED ( opline - > op1 ) ;
if ( expr ) {
2010-11-24 20:19:56 +08:00
if ( expr - > op_type ! = IS_CONST ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " '%s' operator with non-constant operand is no longer supported " , op = = ZEND_BRK ? " break " : " continue " ) ;
2010-11-24 20:19:56 +08:00
} else if ( Z_TYPE ( expr - > u . constant ) ! = IS_LONG | | Z_LVAL ( expr - > u . constant ) < 1 ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " '%s' operator accepts only positive numbers " , op = = ZEND_BRK ? " break " : " continue " ) ;
2010-11-24 20:19:56 +08:00
}
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op2 , expr ) ;
1999-04-08 02:10:10 +08:00
} else {
2010-04-20 18:57:45 +08:00
LITERAL_LONG ( opline - > op2 , 1 ) ;
opline - > op2_type = IS_CONST ;
1999-04-08 02:10:10 +08:00
}
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_switch_cond ( const znode * cond TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
zend_switch_entry switch_entry ;
2000-08-11 04:42:57 +08:00
1999-04-08 02:10:10 +08:00
switch_entry . cond = * cond ;
switch_entry . default_case = - 1 ;
2004-08-24 04:16:35 +08:00
switch_entry . control_var = - 1 ;
2014-05-01 02:28:02 +08:00
zend_stack_push ( & CG ( switch_cond_stack ) , ( void * ) & switch_entry ) ;
1999-04-08 02:10:10 +08:00
2001-07-28 18:51:54 +08:00
do_begin_loop ( TSRMLS_C ) ;
1999-04-08 02:10:10 +08:00
INC_BPC ( CG ( active_op_array ) ) ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_switch_end ( const znode * case_list TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
zend_op * opline ;
2014-05-01 02:48:02 +08:00
zend_switch_entry * switch_entry_ptr = zend_stack_top ( & CG ( switch_cond_stack ) ) ;
1999-04-08 02:10:10 +08:00
2004-10-09 02:50:00 +08:00
/* add code to jmp to default case */
if ( switch_entry_ptr - > default_case ! = - 1 ) {
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
opline - > opcode = ZEND_JMP ;
SET_UNUSED ( opline - > op1 ) ;
SET_UNUSED ( opline - > op2 ) ;
2010-04-20 18:57:45 +08:00
opline - > op1 . opline_num = switch_entry_ptr - > default_case ;
2004-10-09 02:50:00 +08:00
}
2000-04-11 02:24:38 +08:00
if ( case_list - > op_type ! = IS_UNUSED ) { /* non-empty switch */
1999-04-08 02:10:10 +08:00
int next_op_number = get_next_op_number ( CG ( active_op_array ) ) ;
2011-01-20 01:17:52 +08:00
2010-04-20 18:57:45 +08:00
CG ( active_op_array ) - > opcodes [ case_list - > u . op . opline_num ] . op1 . opline_num = next_op_number ;
1999-04-08 02:10:10 +08:00
}
/* remember break/continue loop information */
2010-09-15 15:38:52 +08:00
CG ( active_op_array ) - > brk_cont_array [ CG ( context ) . current_brk_cont ] . cont = CG ( active_op_array ) - > brk_cont_array [ CG ( context ) . current_brk_cont ] . brk = get_next_op_number ( CG ( active_op_array ) ) ;
CG ( context ) . current_brk_cont = CG ( active_op_array ) - > brk_cont_array [ CG ( context ) . current_brk_cont ] . parent ;
1999-04-08 02:10:10 +08:00
2000-03-30 06:28:04 +08:00
if ( switch_entry_ptr - > cond . op_type = = IS_VAR | | switch_entry_ptr - > cond . op_type = = IS_TMP_VAR ) {
/* emit free for the switch condition*/
2001-07-28 18:51:54 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
2008-05-05 19:03:35 +08:00
opline - > opcode = ( switch_entry_ptr - > cond . op_type = = IS_TMP_VAR ) ? ZEND_FREE : ZEND_SWITCH_FREE ;
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op1 , & switch_entry_ptr - > cond ) ;
2000-03-30 06:28:04 +08:00
SET_UNUSED ( opline - > op2 ) ;
}
1999-04-08 02:10:10 +08:00
if ( switch_entry_ptr - > cond . op_type = = IS_CONST ) {
zval_dtor ( & switch_entry_ptr - > cond . u . constant ) ;
}
zend_stack_del_top ( & CG ( switch_cond_stack ) ) ;
DEC_BPC ( CG ( active_op_array ) ) ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_case_before_statement ( const znode * case_list , znode * case_token , znode * case_expr TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2001-07-28 18:51:54 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
int next_op_number ;
2014-05-01 02:48:02 +08:00
zend_switch_entry * switch_entry_ptr = zend_stack_top ( & CG ( switch_cond_stack ) ) ;
1999-04-08 02:10:10 +08:00
znode result ;
2004-08-24 04:16:35 +08:00
if ( switch_entry_ptr - > control_var = = - 1 ) {
switch_entry_ptr - > control_var = get_temporary_variable ( CG ( active_op_array ) ) ;
}
1999-04-08 02:10:10 +08:00
opline - > opcode = ZEND_CASE ;
2010-04-20 18:57:45 +08:00
opline - > result . var = switch_entry_ptr - > control_var ;
opline - > result_type = IS_TMP_VAR ;
SET_NODE ( opline - > op1 , & switch_entry_ptr - > cond ) ;
SET_NODE ( opline - > op2 , case_expr ) ;
if ( opline - > op1_type = = IS_CONST ) {
zval_copy_ctor ( & CONSTANT ( opline - > op1 . constant ) ) ;
1999-04-08 02:10:10 +08:00
}
2010-04-20 18:57:45 +08:00
GET_NODE ( & result , opline - > result ) ;
2006-05-10 07:53:23 +08:00
1999-04-08 02:10:10 +08:00
next_op_number = get_next_op_number ( CG ( active_op_array ) ) ;
2001-07-28 18:51:54 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
opline - > opcode = ZEND_JMPZ ;
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op1 , & result ) ;
1999-04-08 02:10:10 +08:00
SET_UNUSED ( opline - > op2 ) ;
2010-04-20 18:57:45 +08:00
case_token - > u . op . opline_num = next_op_number ;
1999-04-08 02:10:10 +08:00
2000-04-11 02:02:40 +08:00
if ( case_list - > op_type = = IS_UNUSED ) {
1999-04-08 02:10:10 +08:00
return ;
}
next_op_number = get_next_op_number ( CG ( active_op_array ) ) ;
2010-04-20 18:57:45 +08:00
CG ( active_op_array ) - > opcodes [ case_list - > u . op . opline_num ] . op1 . opline_num = next_op_number ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_case_after_statement ( znode * result , const znode * case_token TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
int next_op_number = get_next_op_number ( CG ( active_op_array ) ) ;
2001-07-28 18:51:54 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
opline - > opcode = ZEND_JMP ;
SET_UNUSED ( opline - > op1 ) ;
SET_UNUSED ( opline - > op2 ) ;
2010-04-20 18:57:45 +08:00
result - > u . op . opline_num = next_op_number ;
1999-04-08 02:10:10 +08:00
2010-04-20 18:57:45 +08:00
switch ( CG ( active_op_array ) - > opcodes [ case_token - > u . op . opline_num ] . opcode ) {
2004-10-09 02:50:00 +08:00
case ZEND_JMP :
2010-04-20 18:57:45 +08:00
CG ( active_op_array ) - > opcodes [ case_token - > u . op . opline_num ] . op1 . opline_num = get_next_op_number ( CG ( active_op_array ) ) ;
2004-10-09 02:50:00 +08:00
break ;
case ZEND_JMPZ :
2010-04-20 18:57:45 +08:00
CG ( active_op_array ) - > opcodes [ case_token - > u . op . opline_num ] . op2 . opline_num = get_next_op_number ( CG ( active_op_array ) ) ;
2004-10-09 02:50:00 +08:00
break ;
1999-04-08 02:10:10 +08:00
}
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_default_before_statement ( const znode * case_list , znode * default_token TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
int next_op_number = get_next_op_number ( CG ( active_op_array ) ) ;
2004-10-09 02:50:00 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
2014-05-01 02:48:02 +08:00
zend_switch_entry * switch_entry_ptr = zend_stack_top ( & CG ( switch_cond_stack ) ) ;
1999-04-08 02:10:10 +08:00
2004-10-09 02:50:00 +08:00
opline - > opcode = ZEND_JMP ;
SET_UNUSED ( opline - > op1 ) ;
SET_UNUSED ( opline - > op2 ) ;
2010-04-20 18:57:45 +08:00
default_token - > u . op . opline_num = next_op_number ;
2004-10-09 02:50:00 +08:00
next_op_number = get_next_op_number ( CG ( active_op_array ) ) ;
1999-04-08 02:10:10 +08:00
switch_entry_ptr - > default_case = next_op_number ;
2000-04-11 02:24:38 +08:00
if ( case_list - > op_type = = IS_UNUSED ) {
1999-04-08 02:10:10 +08:00
return ;
}
2010-04-20 18:57:45 +08:00
CG ( active_op_array ) - > opcodes [ case_list - > u . op . opline_num ] . op1 . opline_num = next_op_number ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_begin_class_declaration ( const znode * class_token , znode * class_name , const znode * parent_class_name TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2001-10-30 01:19:02 +08:00
zend_op * opline ;
2002-09-25 03:05:53 +08:00
int doing_inheritance = 0 ;
2006-12-21 10:09:36 +08:00
zend_class_entry * new_class_entry ;
2014-02-10 14:04:30 +08:00
zend_string * lcname ;
2007-11-12 23:52:22 +08:00
int error = 0 ;
2014-02-10 14:04:30 +08:00
zval * ns_name , key ;
2001-10-30 01:19:02 +08:00
2004-01-12 15:15:55 +08:00
if ( CG ( active_class_entry ) ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Class declarations may not be nested " ) ;
2004-01-12 15:15:55 +08:00
return ;
}
2014-02-10 14:04:30 +08:00
lcname = STR_ALLOC ( Z_STRLEN ( class_name - > u . constant ) , 0 ) ;
zend_str_tolower_copy ( lcname - > val , Z_STRVAL ( class_name - > u . constant ) , Z_STRLEN ( class_name - > u . constant ) ) ;
2006-12-21 10:09:36 +08:00
2014-02-10 14:04:30 +08:00
if ( ! ( strcmp ( lcname - > val , " self " ) & & strcmp ( lcname - > val , " parent " ) ) ) {
STR_FREE ( lcname ) ;
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use '%s' as class name as it is reserved " , Z_STRVAL ( class_name - > u . constant ) ) ;
2002-12-07 23:51:25 +08:00
}
2003-02-11 00:11:24 +08:00
2007-09-29 03:52:53 +08:00
/* Class name must not conflict with import names */
if ( CG ( current_import ) & &
2014-02-10 14:04:30 +08:00
( ns_name = zend_hash_find ( CG ( current_import ) , lcname ) ) ! = NULL ) {
2007-11-12 23:52:22 +08:00
error = 1 ;
2007-09-29 03:52:53 +08:00
}
2014-02-10 14:04:30 +08:00
if ( Z_TYPE ( CG ( current_namespace ) ) ! = IS_UNDEF ) {
2007-09-29 03:52:53 +08:00
/* Prefix class name with name of current namespace */
znode tmp ;
2013-01-09 21:16:47 +08:00
tmp . op_type = IS_CONST ;
2014-02-10 14:04:30 +08:00
ZVAL_DUP ( & tmp . u . constant , & CG ( current_namespace ) ) ;
2007-09-29 03:52:53 +08:00
zend_do_build_namespace_name ( & tmp , & tmp , class_name TSRMLS_CC ) ;
2013-01-04 11:02:21 +08:00
* class_name = tmp ;
2014-02-10 14:04:30 +08:00
STR_FREE ( lcname ) ;
2014-02-19 16:03:01 +08:00
lcname = STR_ALLOC ( Z_STRLEN ( class_name - > u . constant ) , 0 ) ;
2014-02-10 14:04:30 +08:00
zend_str_tolower_copy ( lcname - > val , Z_STRVAL ( class_name - > u . constant ) , Z_STRLEN ( class_name - > u . constant ) ) ;
2007-09-29 03:52:53 +08:00
}
2007-11-12 23:52:22 +08:00
if ( error ) {
2014-02-10 14:04:30 +08:00
char * tmp = zend_str_tolower_dup ( Z_STRVAL_P ( ns_name ) , Z_STRLEN_P ( ns_name ) ) ;
2007-11-12 23:52:22 +08:00
2014-02-10 14:04:30 +08:00
if ( Z_STRLEN_P ( ns_name ) ! = Z_STRLEN ( class_name - > u . constant ) | |
memcmp ( tmp , lcname - > val , Z_STRLEN ( class_name - > u . constant ) ) ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot declare class %s because the name is already in use " , Z_STRVAL ( class_name - > u . constant ) ) ;
2007-11-12 23:52:22 +08:00
}
efree ( tmp ) ;
}
2006-12-21 10:09:36 +08:00
new_class_entry = emalloc ( sizeof ( zend_class_entry ) ) ;
2003-03-10 11:04:02 +08:00
new_class_entry - > type = ZEND_USER_CLASS ;
2014-02-10 14:04:30 +08:00
new_class_entry - > name = zend_new_interned_string ( Z_STR ( class_name - > u . constant ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
2003-02-16 19:34:49 +08:00
zend_initialize_class_data ( new_class_entry , 1 TSRMLS_CC ) ;
2010-09-15 15:38:52 +08:00
new_class_entry - > info . user . filename = zend_get_compiled_filename ( TSRMLS_C ) ;
new_class_entry - > info . user . line_start = class_token - > u . op . opline_num ;
2010-04-20 18:57:45 +08:00
new_class_entry - > ce_flags | = class_token - > EA ;
1999-04-08 02:10:10 +08:00
2004-02-12 06:13:39 +08:00
if ( parent_class_name & & parent_class_name - > op_type ! = IS_UNUSED ) {
2010-04-20 18:57:45 +08:00
switch ( parent_class_name - > EA ) {
2005-06-24 16:45:17 +08:00
case ZEND_FETCH_CLASS_SELF :
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use 'self' as class name as it is reserved " ) ;
2005-06-24 16:45:17 +08:00
break ;
case ZEND_FETCH_CLASS_PARENT :
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use 'parent' as class name as it is reserved " ) ;
2005-06-24 16:45:17 +08:00
break ;
2007-09-29 15:28:34 +08:00
case ZEND_FETCH_CLASS_STATIC :
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use 'static' as class name as it is reserved " ) ;
2007-09-29 15:28:34 +08:00
break ;
2005-06-24 16:45:17 +08:00
default :
break ;
}
2002-09-25 03:05:53 +08:00
doing_inheritance = 1 ;
2001-10-30 01:19:02 +08:00
}
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
2010-04-20 18:57:45 +08:00
opline - > op1_type = IS_CONST ;
2014-02-10 14:04:30 +08:00
build_runtime_defined_function_key ( & key , lcname - > val , lcname - > len TSRMLS_CC ) ;
2010-09-15 15:38:52 +08:00
opline - > op1 . constant = zend_add_literal ( CG ( active_op_array ) , & key TSRMLS_CC ) ;
2013-01-28 10:02:51 +08:00
2010-04-20 18:57:45 +08:00
opline - > op2_type = IS_CONST ;
2006-05-10 07:53:23 +08:00
2002-09-25 03:05:53 +08:00
if ( doing_inheritance ) {
2012-08-22 18:32:03 +08:00
/* Make sure a trait does not try to extend a class */
if ( ( new_class_entry - > ce_flags & ZEND_ACC_TRAIT ) = = ZEND_ACC_TRAIT ) {
2014-02-19 18:35:28 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " A trait (%s) cannot extend a class. Traits can only be composed from other traits with the 'use' keyword. Error " , new_class_entry - > name - > val ) ;
2012-08-22 18:32:03 +08:00
}
2010-04-20 18:57:45 +08:00
opline - > extended_value = parent_class_name - > u . op . var ;
2002-09-25 03:05:53 +08:00
opline - > opcode = ZEND_DECLARE_INHERITED_CLASS ;
1999-07-09 00:55:27 +08:00
} else {
2002-09-25 03:05:53 +08:00
opline - > opcode = ZEND_DECLARE_CLASS ;
1999-07-09 00:55:27 +08:00
}
2002-09-25 03:05:53 +08:00
2014-02-10 14:04:30 +08:00
LITERAL_STR ( opline - > op2 , lcname ) ;
2013-01-28 10:02:51 +08:00
2014-02-10 14:04:30 +08:00
zend_hash_update_ptr ( CG ( class_table ) , Z_STR ( key ) , new_class_entry ) ;
2002-03-12 18:08:47 +08:00
CG ( active_class_entry ) = new_class_entry ;
2003-03-05 19:14:44 +08:00
2010-04-20 18:57:45 +08:00
opline - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
opline - > result_type = IS_VAR ;
GET_NODE ( & CG ( implementing_class ) , opline - > result ) ;
2003-04-03 00:51:49 +08:00
if ( CG ( doc_comment ) ) {
2010-09-15 15:38:52 +08:00
CG ( active_class_entry ) - > info . user . doc_comment = CG ( doc_comment ) ;
2005-06-08 02:11:56 +08:00
CG ( doc_comment ) = NULL ;
2003-04-03 00:51:49 +08:00
}
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
static void do_verify_abstract_class ( TSRMLS_D ) /* { { { */
2003-03-07 06:53:23 +08:00
{
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
opline - > opcode = ZEND_VERIFY_ABSTRACT_CLASS ;
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op1 , & CG ( implementing_class ) ) ;
2004-03-22 23:51:07 +08:00
SET_UNUSED ( opline - > op2 ) ;
2003-03-07 06:53:23 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2003-03-07 06:53:23 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_end_class_declaration ( const znode * class_token , const znode * parent_token TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2003-05-30 03:00:40 +08:00
zend_class_entry * ce = CG ( active_class_entry ) ;
2003-08-23 23:38:58 +08:00
if ( ce - > constructor ) {
2004-01-25 00:59:24 +08:00
ce - > constructor - > common . fn_flags | = ZEND_ACC_CTOR ;
2003-09-02 21:26:25 +08:00
if ( ce - > constructor - > common . fn_flags & ZEND_ACC_STATIC ) {
2014-02-21 21:27:53 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Constructor %s::%s() cannot be static " , ce - > name - > val , ce - > constructor - > common . function_name - > val ) ;
2003-09-02 21:26:25 +08:00
}
2003-08-23 23:38:58 +08:00
}
if ( ce - > destructor ) {
2004-01-25 00:59:24 +08:00
ce - > destructor - > common . fn_flags | = ZEND_ACC_DTOR ;
2003-09-02 21:26:25 +08:00
if ( ce - > destructor - > common . fn_flags & ZEND_ACC_STATIC ) {
2014-02-21 21:27:53 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Destructor %s::%s() cannot be static " , ce - > name - > val , ce - > destructor - > common . function_name - > val ) ;
2003-09-02 21:26:25 +08:00
}
2003-08-23 23:38:58 +08:00
}
2004-01-24 04:52:39 +08:00
if ( ce - > clone ) {
2004-01-25 00:59:24 +08:00
ce - > clone - > common . fn_flags | = ZEND_ACC_CLONE ;
2004-01-24 04:52:39 +08:00
if ( ce - > clone - > common . fn_flags & ZEND_ACC_STATIC ) {
2014-02-21 21:27:53 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Clone method %s::%s() cannot be static " , ce - > name - > val , ce - > clone - > common . function_name - > val ) ;
2004-01-24 04:52:39 +08:00
}
}
2003-08-23 23:38:58 +08:00
2010-09-15 15:38:52 +08:00
ce - > info . user . line_end = zend_get_compiled_lineno ( TSRMLS_C ) ;
2013-01-28 10:02:51 +08:00
2010-05-08 00:29:15 +08:00
/* Check for traits and proceed like with interfaces.
* The only difference will be a combined handling of them in the end .
* Thus , we need another opcode here . */
if ( ce - > num_traits > 0 ) {
zend_op * opline ;
ce - > traits = NULL ;
ce - > num_traits = 0 ;
ce - > ce_flags | = ZEND_ACC_IMPLEMENT_TRAITS ;
/* opcode generation: */
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
opline - > opcode = ZEND_BIND_TRAITS ;
SET_NODE ( opline - > op1 , & CG ( implementing_class ) ) ;
}
2003-04-01 04:42:01 +08:00
2004-03-10 00:38:37 +08:00
if ( ! ( ce - > ce_flags & ( ZEND_ACC_INTERFACE | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS ) )
2013-01-09 21:16:47 +08:00
& & ( parent_token | | ( ce - > num_interfaces > 0 ) ) ) {
2004-02-27 17:14:55 +08:00
zend_verify_abstract_class ( ce TSRMLS_CC ) ;
2012-12-25 14:23:08 +08:00
if ( ce - > num_interfaces & & ! ( ce - > ce_flags & ZEND_ACC_IMPLEMENT_TRAITS ) ) {
2004-02-27 17:14:55 +08:00
do_verify_abstract_class ( TSRMLS_C ) ;
}
2003-03-07 06:53:23 +08:00
}
2006-06-07 17:21:06 +08:00
/* Inherit interfaces; reset number to zero, we need it for above check and
2013-01-28 10:02:51 +08:00
* will restore it during actual implementation .
2008-03-12 17:46:42 +08:00
* The ZEND_ACC_IMPLEMENT_INTERFACES flag disables double call to
* zend_verify_abstract_class ( ) */
2006-06-07 17:21:06 +08:00
if ( ce - > num_interfaces > 0 ) {
ce - > interfaces = NULL ;
ce - > num_interfaces = 0 ;
2008-03-12 17:46:42 +08:00
ce - > ce_flags | = ZEND_ACC_IMPLEMENT_INTERFACES ;
2006-06-07 17:21:06 +08:00
}
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
2003-02-16 19:12:43 +08:00
CG ( active_class_entry ) = NULL ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_implements_interface ( znode * interface_name TSRMLS_DC ) /* { { { */
2003-03-05 19:14:44 +08:00
{
2005-06-24 16:45:17 +08:00
zend_op * opline ;
2003-03-05 19:14:44 +08:00
2010-04-23 07:16:15 +08:00
/* Traits can not implement interfaces */
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
if ( ( CG ( active_class_entry ) - > ce_flags & ZEND_ACC_TRAIT ) = = ZEND_ACC_TRAIT ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use '%s' as interface on '%s' since it is a Trait " ,
2011-01-20 01:17:52 +08:00
Z_STRVAL ( interface_name - > u . constant ) ,
2014-02-21 21:27:53 +08:00
CG ( active_class_entry ) - > 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
}
2008-03-12 18:32:12 +08:00
switch ( zend_get_class_fetch_type ( Z_STRVAL ( interface_name - > u . constant ) , Z_STRLEN ( interface_name - > u . constant ) ) ) {
2005-06-24 16:45:17 +08:00
case ZEND_FETCH_CLASS_SELF :
case ZEND_FETCH_CLASS_PARENT :
2007-09-29 15:28:34 +08:00
case ZEND_FETCH_CLASS_STATIC :
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use '%s' as interface name as it is reserved " , Z_STRVAL ( interface_name - > u . constant ) ) ;
2007-09-29 15:28:34 +08:00
break ;
2005-06-24 16:45:17 +08:00
default :
break ;
}
2006-05-10 07:53:23 +08:00
2005-06-24 16:45:17 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
2003-03-05 19:14:44 +08:00
opline - > opcode = ZEND_ADD_INTERFACE ;
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op1 , & CG ( implementing_class ) ) ;
2013-09-13 18:18:39 +08:00
zend_resolve_class_name ( interface_name TSRMLS_CC ) ;
2008-03-12 18:32:12 +08:00
opline - > extended_value = ( opline - > extended_value & ~ ZEND_FETCH_CLASS_MASK ) | ZEND_FETCH_CLASS_INTERFACE ;
2010-04-21 22:58:33 +08:00
opline - > op2_type = IS_CONST ;
2010-04-21 23:08:10 +08:00
opline - > op2 . constant = zend_add_class_name_literal ( CG ( active_op_array ) , & interface_name - > u . constant TSRMLS_CC ) ;
2008-03-12 18:32:12 +08:00
CG ( active_class_entry ) - > num_interfaces + + ;
2003-03-05 19:14:44 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2003-03-05 19:14:44 +08:00
2012-12-25 14:23:08 +08:00
void zend_do_use_trait ( znode * trait_name TSRMLS_DC ) /* { { { */
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
{
zend_op * opline ;
2012-12-25 14:23:08 +08:00
2011-12-19 18:05:48 +08:00
if ( ( CG ( active_class_entry ) - > ce_flags & ZEND_ACC_INTERFACE ) ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR ,
2011-12-19 18:05:48 +08:00
" Cannot use traits inside of interfaces. %s is used in %s " ,
2014-02-21 21:27:53 +08:00
Z_STRVAL ( trait_name - > u . constant ) , CG ( active_class_entry ) - > name - > val ) ;
2011-12-19 18:05:48 +08:00
}
2011-11-01 08:39:10 +08:00
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
switch ( zend_get_class_fetch_type ( Z_STRVAL ( trait_name - > u . constant ) , Z_STRLEN ( trait_name - > u . constant ) ) ) {
case ZEND_FETCH_CLASS_SELF :
case ZEND_FETCH_CLASS_PARENT :
case ZEND_FETCH_CLASS_STATIC :
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use '%s' as trait name as it is reserved " , Z_STRVAL ( trait_name - > u . constant ) ) ;
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
break ;
default :
break ;
}
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
opline - > opcode = ZEND_ADD_TRAIT ;
2010-04-23 16:56:03 +08:00
SET_NODE ( opline - > op1 , & CG ( implementing_class ) ) ;
2013-09-13 18:18:39 +08:00
zend_resolve_class_name ( trait_name TSRMLS_CC ) ;
2010-05-05 02:21:00 +08:00
opline - > extended_value = ZEND_FETCH_CLASS_TRAIT ;
2010-04-23 16:56:03 +08:00
opline - > op2_type = IS_CONST ;
opline - > op2 . constant = zend_add_class_name_literal ( CG ( active_op_array ) , & trait_name - > u . constant TSRMLS_CC ) ;
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
CG ( active_class_entry ) - > num_traits + + ;
}
/* }}} */
2014-02-17 21:59:18 +08:00
ZEND_API zend_string * zend_mangle_property_name ( const char * src1 , int src1_length , const char * src2 , int src2_length , int internal ) /* { { { */
2002-02-21 19:50:44 +08:00
{
2014-02-17 21:59:18 +08:00
zend_string * prop_name ;
2002-07-16 02:09:56 +08:00
int prop_name_length ;
2006-05-10 07:53:23 +08:00
2002-07-16 02:09:56 +08:00
prop_name_length = 1 + src1_length + 1 + src2_length ;
2014-02-17 21:59:18 +08:00
prop_name = STR_ALLOC ( prop_name_length , internal ) ;
prop_name - > val [ 0 ] = ' \0 ' ;
memcpy ( prop_name - > val + 1 , src1 , src1_length + 1 ) ;
memcpy ( prop_name - > val + 1 + src1_length + 1 , src2 , src2_length + 1 ) ;
return prop_name ;
2002-02-21 19:50:44 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
static int zend_strnlen ( const char * s , int maxlen ) /* { { { */
2005-09-17 01:05:09 +08:00
{
2006-07-25 01:58:32 +08:00
int len = 0 ;
while ( * s + + & & maxlen - - ) len + + ;
return len ;
2005-09-17 01:05:09 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2005-09-17 01:05:09 +08:00
2013-01-14 16:23:22 +08:00
ZEND_API int zend_unmangle_property_name_ex ( const char * mangled_property , int len , const char * * class_name , const char * * prop_name , int * prop_len ) /* { { { */
2003-06-09 02:53:58 +08:00
{
2006-07-25 01:58:32 +08:00
int class_name_len ;
* class_name = NULL ;
2003-06-09 02:53:58 +08:00
if ( mangled_property [ 0 ] ! = 0 ) {
* prop_name = mangled_property ;
2013-01-14 16:23:22 +08:00
if ( prop_len ) {
* prop_len = len ;
}
2006-07-25 01:58:32 +08:00
return SUCCESS ;
}
2006-07-25 06:36:21 +08:00
if ( len < 3 | | mangled_property [ 1 ] = = 0 ) {
2006-07-25 01:58:32 +08:00
zend_error ( E_NOTICE , " Illegal member variable name " ) ;
* prop_name = mangled_property ;
2013-01-14 16:23:22 +08:00
if ( prop_len ) {
* prop_len = len ;
}
2006-07-25 01:58:32 +08:00
return FAILURE ;
2003-06-09 02:53:58 +08:00
}
2013-01-14 16:23:22 +08:00
class_name_len = zend_strnlen ( mangled_property + 1 , - - len - 1 ) + 1 ;
2006-07-25 01:58:32 +08:00
if ( class_name_len > = len | | mangled_property [ class_name_len ] ! = 0 ) {
zend_error ( E_NOTICE , " Corrupt member variable name " ) ;
* prop_name = mangled_property ;
2013-01-14 16:23:22 +08:00
if ( prop_len ) {
* prop_len = len + 1 ;
}
2006-07-25 01:58:32 +08:00
return FAILURE ;
}
2013-01-14 16:23:22 +08:00
* class_name = mangled_property + 1 ;
* prop_name = ( * class_name ) + class_name_len ;
if ( prop_len ) {
* prop_len = len - class_name_len ;
}
2006-07-25 01:58:32 +08:00
return SUCCESS ;
2003-06-09 02:53:58 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2003-06-09 02:53:58 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_declare_property ( znode * var_name , znode * value , zend_uint access_type TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2014-02-10 14:04:30 +08:00
zval property ;
2003-02-10 20:46:58 +08:00
zend_property_info * existing_property_info ;
2014-02-10 14:04:30 +08:00
zend_string * comment = NULL ;
1999-12-27 05:21:33 +08:00
2003-03-05 19:14:44 +08:00
if ( CG ( active_class_entry ) - > ce_flags & ZEND_ACC_INTERFACE ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Interfaces may not include member variables " ) ;
2003-03-05 19:14:44 +08:00
}
2003-02-11 17:48:37 +08:00
if ( access_type & ZEND_ACC_ABSTRACT ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Properties cannot be declared abstract " ) ;
2003-02-11 17:48:37 +08:00
}
2003-04-20 22:52:40 +08:00
if ( access_type & ZEND_ACC_FINAL ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot declare property %s::$%s final, the final modifier is allowed only for methods and classes " ,
2014-02-19 16:03:01 +08:00
CG ( active_class_entry ) - > name - > val , Z_STRVAL ( var_name - > u . constant ) ) ;
2003-04-20 22:52:40 +08:00
}
2014-02-10 14:04:30 +08:00
if ( ( existing_property_info = zend_hash_find_ptr ( & CG ( active_class_entry ) - > properties_info , Z_STR ( var_name - > u . constant ) ) ) ! = NULL ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot redeclare %s::$%s " , CG ( active_class_entry ) - > name - > val , Z_STRVAL ( var_name - > u . constant ) ) ;
2003-02-10 20:46:58 +08:00
}
1999-04-08 02:10:10 +08:00
2002-02-14 12:01:53 +08:00
if ( value ) {
2014-02-10 14:04:30 +08:00
ZVAL_COPY_VALUE ( & property , & value - > u . constant ) ;
2002-02-14 12:01:53 +08:00
} else {
2014-02-10 14:04:30 +08:00
ZVAL_NULL ( & property ) ;
2002-02-14 12:01:53 +08:00
}
2005-04-20 06:04:59 +08:00
if ( CG ( doc_comment ) ) {
2005-06-08 02:11:56 +08:00
comment = CG ( doc_comment ) ;
CG ( doc_comment ) = NULL ;
2005-04-20 06:04:59 +08:00
}
2014-02-10 14:04:30 +08:00
Z_STR ( var_name - > u . constant ) = zend_new_interned_string ( Z_STR ( var_name - > u . constant ) TSRMLS_CC ) ;
2014-04-03 19:26:23 +08:00
if ( IS_INTERNED ( Z_STR ( var_name - > u . constant ) ) ) {
Z_TYPE_FLAGS ( var_name - > u . constant ) & = ~ ( IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE ) ;
}
2014-02-10 14:04:30 +08:00
zend_declare_property_ex ( CG ( active_class_entry ) , Z_STR ( var_name - > u . constant ) , & property , access_type , comment TSRMLS_CC ) ;
2014-03-31 20:09:45 +08:00
STR_RELEASE ( Z_STR ( var_name - > u . constant ) ) ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_declare_class_constant ( znode * var_name , znode * value TSRMLS_DC ) /* { { { */
2002-12-07 01:09:44 +08:00
{
2014-05-07 19:03:56 +08:00
if ( ( Z_TYPE ( value - > u . constant ) = = IS_ARRAY ) | |
( Z_TYPE ( value - > u . constant ) = = IS_CONSTANT_AST & &
Z_ASTVAL ( value - > u . constant ) - > kind = = ZEND_INIT_ARRAY ) ) {
2014-05-07 07:26:13 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Arrays are not allowed in class constants " ) ;
return ;
}
2010-05-07 19:09:35 +08:00
if ( ( CG ( active_class_entry ) - > ce_flags & ZEND_ACC_TRAIT ) = = ZEND_ACC_TRAIT ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Traits cannot have constants " ) ;
2010-05-07 19:09:35 +08:00
return ;
2004-01-09 22:02:33 +08:00
}
2006-05-10 07:53:23 +08:00
2014-02-22 03:51:08 +08:00
Z_STR ( var_name - > u . constant ) = zend_new_interned_string ( Z_STR ( var_name - > u . constant ) TSRMLS_CC ) ;
2014-04-03 19:26:23 +08:00
if ( IS_INTERNED ( Z_STR ( var_name - > u . constant ) ) ) {
Z_TYPE_FLAGS ( var_name - > u . constant ) & = ~ ( IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE ) ;
}
2014-06-17 03:32:58 +08:00
if ( Z_CONSTANT ( value - > u . constant ) ) {
CG ( active_class_entry ) - > ce_flags & = ~ ZEND_ACC_CONSTANTS_UPDATED ;
}
if ( zend_hash_add ( & CG ( active_class_entry ) - > constants_table , Z_STR ( var_name - > u . constant ) , & value - > u . constant ) = = NULL ) {
2014-02-10 14:04:30 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot redefine class constant %s::%s " , CG ( active_class_entry ) - > name - > val , Z_STRVAL ( var_name - > u . constant ) ) ;
2004-09-10 14:13:13 +08:00
}
2002-12-07 01:09:44 +08:00
FREE_PNODE ( var_name ) ;
2013-01-28 10:02:51 +08:00
2009-11-15 03:17:22 +08:00
if ( CG ( doc_comment ) ) {
2014-02-10 14:04:30 +08:00
STR_RELEASE ( CG ( doc_comment ) ) ;
2009-11-15 03:17:22 +08:00
CG ( doc_comment ) = NULL ;
}
2002-12-07 01:09:44 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2002-12-07 01:09:44 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_fetch_property ( znode * result , znode * object , znode * property TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
1999-09-20 23:44:30 +08:00
zend_op opline ;
2014-05-01 02:48:02 +08:00
zend_llist * fetch_list_ptr = zend_stack_top ( & CG ( bp_stack ) ) ;
2006-05-10 07:53:23 +08:00
2008-05-07 20:04:39 +08:00
if ( object - > op_type = = IS_CV ) {
2010-04-20 18:57:45 +08:00
if ( object - > u . op . var = = CG ( active_op_array ) - > this_var ) {
object - > op_type = IS_UNUSED ; /* this means $this for objects */
2011-01-20 01:17:52 +08:00
}
2008-05-07 20:04:39 +08:00
} else if ( fetch_list_ptr - > count = = 1 ) {
zend_llist_element * le = fetch_list_ptr - > head ;
zend_op * opline_ptr = ( zend_op * ) le - > data ;
2002-10-08 05:20:23 +08:00
2004-02-04 22:25:25 +08:00
if ( opline_is_fetch_this ( opline_ptr TSRMLS_CC ) ) {
2010-04-20 18:57:45 +08:00
zend_del_literal ( CG ( active_op_array ) , opline_ptr - > op1 . constant ) ;
2002-10-17 02:06:36 +08:00
SET_UNUSED ( opline_ptr - > op1 ) ; /* this means $this for objects */
2010-04-20 18:57:45 +08:00
SET_NODE ( opline_ptr - > op2 , property ) ;
2002-10-17 02:06:36 +08:00
/* if it was usual fetch, we change it to object fetch */
2002-11-30 19:20:25 +08:00
switch ( opline_ptr - > opcode ) {
2002-10-17 02:06:36 +08:00
case ZEND_FETCH_W :
opline_ptr - > opcode = ZEND_FETCH_OBJ_W ;
break ;
case ZEND_FETCH_R :
opline_ptr - > opcode = ZEND_FETCH_OBJ_R ;
break ;
case ZEND_FETCH_RW :
opline_ptr - > opcode = ZEND_FETCH_OBJ_RW ;
break ;
case ZEND_FETCH_IS :
opline_ptr - > opcode = ZEND_FETCH_OBJ_IS ;
break ;
case ZEND_FETCH_UNSET :
opline_ptr - > opcode = ZEND_FETCH_OBJ_UNSET ;
break ;
case ZEND_FETCH_FUNC_ARG :
opline_ptr - > opcode = ZEND_FETCH_OBJ_FUNC_ARG ;
break ;
}
2010-04-20 18:57:45 +08:00
if ( opline_ptr - > op2_type = = IS_CONST & & Z_TYPE ( CONSTANT ( opline_ptr - > op2 . constant ) ) = = IS_STRING ) {
2010-05-24 22:11:39 +08:00
GET_POLYMORPHIC_CACHE_SLOT ( opline_ptr - > op2 . constant ) ;
2010-04-20 18:57:45 +08:00
}
GET_NODE ( result , opline_ptr - > result ) ;
2002-01-05 23:18:30 +08:00
return ;
}
}
1999-04-08 02:10:10 +08:00
2010-08-25 17:14:36 +08:00
if ( zend_is_function_or_method_call ( object ) ) {
init_op ( & opline TSRMLS_CC ) ;
opline . opcode = ZEND_SEPARATE ;
SET_NODE ( opline . op1 , object ) ;
SET_UNUSED ( opline . op2 ) ;
opline . result_type = IS_VAR ;
opline . result . var = opline . op1 . var ;
zend_llist_add_element ( fetch_list_ptr , & opline ) ;
}
2001-07-28 18:51:54 +08:00
init_op ( & opline TSRMLS_CC ) ;
1999-09-20 23:44:30 +08:00
opline . opcode = ZEND_FETCH_OBJ_W ; /* the backpatching routine assumes W */
2010-04-20 18:57:45 +08:00
opline . result_type = IS_VAR ;
opline . result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
SET_NODE ( opline . op1 , object ) ;
SET_NODE ( opline . op2 , property ) ;
if ( opline . op2_type = = IS_CONST & & Z_TYPE ( CONSTANT ( opline . op2 . constant ) ) = = IS_STRING ) {
2010-05-24 22:11:39 +08:00
GET_POLYMORPHIC_CACHE_SLOT ( opline . op2 . constant ) ;
2010-04-20 18:57:45 +08:00
}
GET_NODE ( result , opline . result ) ;
1999-04-08 02:10:10 +08:00
1999-09-20 23:44:30 +08:00
zend_llist_add_element ( fetch_list_ptr , & opline ) ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_halt_compiler_register ( TSRMLS_D ) /* { { { */
2007-04-04 08:42:42 +08:00
{
2014-02-17 21:59:18 +08:00
zend_string * name ;
2014-02-10 14:04:30 +08:00
zend_string * cfilename ;
2007-04-04 08:42:42 +08:00
char haltoff [ ] = " __COMPILER_HALT_OFFSET__ " ;
2013-01-28 10:02:51 +08:00
2011-11-17 01:41:40 +08:00
if ( CG ( has_bracketed_namespaces ) & & CG ( in_namespace ) ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " __HALT_COMPILER() can only be used from the outermost scope " ) ;
2011-11-17 01:41:40 +08:00
}
2013-01-28 10:02:51 +08:00
2007-04-04 08:42:42 +08:00
cfilename = zend_get_compiled_filename ( TSRMLS_C ) ;
2014-02-17 21:59:18 +08:00
name = zend_mangle_property_name ( haltoff , sizeof ( haltoff ) - 1 , cfilename - > val , cfilename - > len , 0 ) ;
zend_register_long_constant ( name - > val , name - > len , zend_get_scanned_file_offset ( TSRMLS_C ) , CONST_CS , 0 TSRMLS_CC ) ;
STR_FREE ( name ) ;
2013-01-28 10:02:51 +08:00
2011-05-20 07:20:47 +08:00
if ( CG ( in_namespace ) ) {
zend_do_end_namespace ( TSRMLS_C ) ;
}
2007-04-04 08:42:42 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2003-06-09 21:51:53 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_push_object ( const znode * object TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2014-05-01 02:28:02 +08:00
zend_stack_push ( & CG ( object_stack ) , object ) ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_pop_object ( znode * object TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2003-06-09 21:51:53 +08:00
if ( object ) {
2014-05-01 02:48:02 +08:00
znode * tmp = zend_stack_top ( & CG ( object_stack ) ) ;
2003-06-09 21:51:53 +08:00
* object = * tmp ;
}
1999-04-08 02:10:10 +08:00
zend_stack_del_top ( & CG ( object_stack ) ) ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_begin_new_object ( znode * new_token , znode * class_type TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2005-06-10 15:56:40 +08:00
zend_op * opline ;
2006-05-10 07:53:23 +08:00
2010-04-20 18:57:45 +08:00
new_token - > u . op . opline_num = get_next_op_number ( CG ( active_op_array ) ) ;
2005-06-10 15:56:40 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
opline - > opcode = ZEND_NEW ;
2012-11-30 17:39:23 +08:00
opline - > extended_value = CG ( context ) . nested_calls ;
2010-04-20 18:57:45 +08:00
opline - > result_type = IS_VAR ;
opline - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
SET_NODE ( opline - > op1 , class_type ) ;
1999-04-08 02:10:10 +08:00
SET_UNUSED ( opline - > op2 ) ;
2006-05-10 07:53:23 +08:00
2014-02-26 06:39:50 +08:00
zend_push_function_call_entry ( NULL TSRMLS_CC ) ;
2012-11-30 17:39:23 +08:00
if ( + + CG ( context ) . nested_calls > CG ( active_op_array ) - > nested_calls ) {
CG ( active_op_array ) - > nested_calls = CG ( context ) . nested_calls ;
}
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-02-26 07:14:50 +08:00
void zend_do_end_new_object ( znode * result , const znode * new_token TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
znode ctor_result ;
2014-02-26 07:14:50 +08:00
zend_do_end_function_call ( NULL , & ctor_result , 1 , 0 TSRMLS_CC ) ;
2001-07-28 18:51:54 +08:00
zend_do_free ( & ctor_result TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
2010-04-20 18:57:45 +08:00
CG ( active_op_array ) - > opcodes [ new_token - > u . op . opline_num ] . op2 . opline_num = get_next_op_number ( CG ( active_op_array ) ) ;
GET_NODE ( result , CG ( active_op_array ) - > opcodes [ new_token - > u . op . opline_num ] . result ) ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2008-08-29 18:17:08 +08:00
static zend_constant * zend_get_ct_const ( const zval * const_name , int all_internal_constants_substitution TSRMLS_DC ) /* { { { */
2006-03-15 17:04:36 +08:00
{
zend_constant * c = NULL ;
2014-02-10 14:04:30 +08:00
char * lookup_name ;
2006-03-15 17:04:36 +08:00
2008-11-04 23:58:55 +08:00
if ( Z_STRVAL_P ( const_name ) [ 0 ] = = ' \\ ' ) {
2014-02-10 14:04:30 +08:00
if ( ( c = zend_hash_str_find_ptr ( EG ( zend_constants ) , Z_STRVAL_P ( const_name ) + 1 , Z_STRLEN_P ( const_name ) - 1 ) ) = = NULL ) {
lookup_name = zend_str_tolower_dup ( Z_STRVAL_P ( const_name ) + 1 , Z_STRLEN_P ( const_name ) - 1 ) ;
if ( ( c = zend_hash_str_find_ptr ( EG ( zend_constants ) , lookup_name , Z_STRLEN_P ( const_name ) - 1 ) ) ! = NULL ) {
2008-11-04 23:58:55 +08:00
if ( ( c - > flags & CONST_CT_SUBST ) & & ! ( c - > flags & CONST_CS ) ) {
efree ( lookup_name ) ;
return c ;
}
}
efree ( lookup_name ) ;
return NULL ;
}
2014-02-10 14:04:30 +08:00
} else if ( ( c = zend_hash_find_ptr ( EG ( zend_constants ) , Z_STR_P ( const_name ) ) ) = = NULL ) {
lookup_name = zend_str_tolower_dup ( Z_STRVAL_P ( const_name ) , Z_STRLEN_P ( const_name ) ) ;
if ( ( c = zend_hash_str_find_ptr ( EG ( zend_constants ) , lookup_name , Z_STRLEN_P ( const_name ) ) ) ! = NULL ) {
2008-07-28 22:12:19 +08:00
if ( ( c - > flags & CONST_CT_SUBST ) & & ! ( c - > flags & CONST_CS ) ) {
2007-09-29 03:52:53 +08:00
efree ( lookup_name ) ;
2008-07-28 22:12:19 +08:00
return c ;
2006-03-15 17:04:36 +08:00
}
}
efree ( lookup_name ) ;
2008-07-28 22:12:19 +08:00
return NULL ;
2006-03-15 17:04:36 +08:00
}
2007-09-29 03:52:53 +08:00
if ( c - > flags & CONST_CT_SUBST ) {
return c ;
}
2008-08-29 18:17:08 +08:00
if ( all_internal_constants_substitution & &
2008-07-31 22:27:43 +08:00
( c - > flags & CONST_PERSISTENT ) & &
2008-07-25 12:54:08 +08:00
! ( CG ( compiler_options ) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION ) & &
2014-04-04 07:55:27 +08:00
! Z_CONSTANT ( c - > value ) ) {
2008-07-25 12:54:08 +08:00
return c ;
}
2007-09-29 03:52:53 +08:00
return NULL ;
}
/* }}} */
2008-08-29 18:17:08 +08:00
static int zend_constant_ct_subst ( znode * result , zval * const_name , int all_internal_constants_substitution TSRMLS_DC ) /* { { { */
2007-09-29 03:52:53 +08:00
{
2008-08-29 18:17:08 +08:00
zend_constant * c = zend_get_ct_const ( const_name , all_internal_constants_substitution TSRMLS_CC ) ;
2007-09-29 03:52:53 +08:00
if ( c ) {
2006-03-15 17:04:36 +08:00
zval_dtor ( const_name ) ;
result - > op_type = IS_CONST ;
result - > u . constant = c - > value ;
zval_copy_ctor ( & result - > u . constant ) ;
return 1 ;
}
return 0 ;
}
2007-09-29 03:52:53 +08:00
/* }}} */
2006-03-15 17:04:36 +08:00
2007-09-29 03:52:53 +08:00
void zend_do_fetch_constant ( znode * result , znode * constant_container , znode * constant_name , int mode , zend_bool check_namespace TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2007-09-29 03:52:53 +08:00
znode tmp ;
2008-11-04 23:58:55 +08:00
zend_op * opline ;
int type ;
2008-11-12 03:45:29 +08:00
char * compound ;
2008-11-04 23:58:55 +08:00
ulong fetch_type = 0 ;
2007-09-29 03:52:53 +08:00
2008-11-04 23:58:55 +08:00
if ( constant_container ) {
switch ( mode ) {
case ZEND_CT :
/* this is a class constant */
type = zend_get_class_fetch_type ( Z_STRVAL ( constant_container - > u . constant ) , Z_STRLEN ( constant_container - > u . constant ) ) ;
2013-01-28 10:02:51 +08:00
2007-10-01 19:25:14 +08:00
if ( ZEND_FETCH_CLASS_STATIC = = type ) {
zend_error ( E_ERROR , " \" static:: \" is not allowed in compile-time constants " ) ;
} else if ( ZEND_FETCH_CLASS_DEFAULT = = type ) {
2013-09-13 18:18:39 +08:00
zend_resolve_class_name ( constant_container TSRMLS_CC ) ;
2007-09-29 03:52:53 +08:00
}
2008-11-04 23:58:55 +08:00
zend_do_build_full_name ( NULL , constant_container , constant_name , 1 TSRMLS_CC ) ;
2001-12-01 00:29:47 +08:00
* result = * constant_container ;
2014-04-03 19:26:23 +08:00
Z_TYPE_INFO ( result - > u . constant ) = IS_CONSTANT_EX ;
if ( IS_INTERNED ( Z_STR ( result - > u . constant ) ) ) {
Z_TYPE_FLAGS ( result - > u . constant ) & = ~ ( IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE ) ;
}
Z_CONST_FLAGS ( result - > u . constant ) = fetch_type ;
2008-11-04 23:58:55 +08:00
break ;
case ZEND_RT :
if ( constant_container - > op_type = = IS_CONST & &
ZEND_FETCH_CLASS_DEFAULT = = zend_get_class_fetch_type ( Z_STRVAL ( constant_container - > u . constant ) , Z_STRLEN ( constant_container - > u . constant ) ) ) {
2013-09-13 18:18:39 +08:00
zend_resolve_class_name ( constant_container TSRMLS_CC ) ;
2008-11-04 23:58:55 +08:00
} else {
zend_do_fetch_class ( & tmp , constant_container TSRMLS_CC ) ;
2007-09-29 03:52:53 +08:00
constant_container = & tmp ;
}
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
opline - > opcode = ZEND_FETCH_CONSTANT ;
2010-04-20 18:57:45 +08:00
opline - > result_type = IS_TMP_VAR ;
opline - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
2010-04-21 22:58:33 +08:00
if ( constant_container - > op_type = = IS_CONST ) {
opline - > op1_type = IS_CONST ;
2010-04-21 23:08:10 +08:00
opline - > op1 . constant = zend_add_class_name_literal ( CG ( active_op_array ) , & constant_container - > u . constant TSRMLS_CC ) ;
2010-04-21 22:58:33 +08:00
} else {
SET_NODE ( opline - > op1 , constant_container ) ;
2010-04-20 18:57:45 +08:00
}
SET_NODE ( opline - > op2 , constant_name ) ;
2010-05-24 22:11:39 +08:00
if ( opline - > op1_type = = IS_CONST ) {
GET_CACHE_SLOT ( opline - > op2 . constant ) ;
} else {
GET_POLYMORPHIC_CACHE_SLOT ( opline - > op2 . constant ) ;
}
2010-04-20 18:57:45 +08:00
GET_NODE ( result , opline - > result ) ;
2008-11-04 23:58:55 +08:00
break ;
}
return ;
}
/* namespace constant */
2008-11-12 03:45:29 +08:00
/* only one that did not contain \ from the start can be converted to string if unknown */
2008-11-04 23:58:55 +08:00
switch ( mode ) {
case ZEND_CT :
2008-11-12 03:45:29 +08:00
compound = memchr ( Z_STRVAL ( constant_name - > u . constant ) , ' \\ ' , Z_STRLEN ( constant_name - > u . constant ) ) ;
2008-11-04 23:58:55 +08:00
/* this is a namespace constant, or an unprefixed constant */
if ( zend_constant_ct_subst ( result , & constant_name - > u . constant , 0 TSRMLS_CC ) ) {
break ;
}
2008-11-12 03:45:29 +08:00
2013-08-30 23:55:43 +08:00
zend_resolve_const_name ( constant_name , & check_namespace TSRMLS_CC ) ;
2008-11-12 03:45:29 +08:00
if ( ! compound ) {
fetch_type | = IS_CONSTANT_UNQUALIFIED ;
2008-11-04 23:58:55 +08:00
}
2008-11-12 03:45:29 +08:00
2008-11-04 23:58:55 +08:00
* result = * constant_name ;
2014-04-03 19:26:23 +08:00
Z_TYPE_INFO ( result - > u . constant ) = IS_CONSTANT_EX ;
if ( IS_INTERNED ( Z_STR ( result - > u . constant ) ) ) {
Z_TYPE_FLAGS ( result - > u . constant ) & = ~ ( IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE ) ;
}
Z_CONST_FLAGS ( result - > u . constant ) = fetch_type ;
2008-11-04 23:58:55 +08:00
break ;
case ZEND_RT :
2008-11-12 03:45:29 +08:00
compound = memchr ( Z_STRVAL ( constant_name - > u . constant ) , ' \\ ' , Z_STRLEN ( constant_name - > u . constant ) ) ;
2008-11-04 23:58:55 +08:00
2013-08-30 23:55:43 +08:00
zend_resolve_const_name ( constant_name , & check_namespace TSRMLS_CC ) ;
2013-01-28 10:02:51 +08:00
2008-11-12 03:45:29 +08:00
if ( zend_constant_ct_subst ( result , & constant_name - > u . constant , 1 TSRMLS_CC ) ) {
break ;
2008-11-04 23:58:55 +08:00
}
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
opline - > opcode = ZEND_FETCH_CONSTANT ;
2010-04-20 18:57:45 +08:00
opline - > result_type = IS_TMP_VAR ;
opline - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
GET_NODE ( result , opline - > result ) ;
2008-11-04 23:58:55 +08:00
SET_UNUSED ( opline - > op1 ) ;
2010-04-22 23:03:17 +08:00
opline - > op2_type = IS_CONST ;
if ( compound ) {
2008-11-12 03:45:29 +08:00
/* the name is unambiguous */
opline - > extended_value = 0 ;
2010-04-22 23:03:17 +08:00
opline - > op2 . constant = zend_add_const_name_literal ( CG ( active_op_array ) , & constant_name - > u . constant , 0 TSRMLS_CC ) ;
2013-01-28 10:02:51 +08:00
} else {
2008-11-12 03:45:29 +08:00
opline - > extended_value = IS_CONSTANT_UNQUALIFIED ;
2014-02-10 14:04:30 +08:00
if ( Z_TYPE ( CG ( current_namespace ) ) ! = IS_UNDEF ) {
2010-04-22 23:03:17 +08:00
opline - > extended_value | = IS_CONSTANT_IN_NAMESPACE ;
opline - > op2 . constant = zend_add_const_name_literal ( CG ( active_op_array ) , & constant_name - > u . constant , 1 TSRMLS_CC ) ;
} else {
opline - > op2 . constant = zend_add_const_name_literal ( CG ( active_op_array ) , & constant_name - > u . constant , 0 TSRMLS_CC ) ;
}
2008-11-12 03:45:29 +08:00
}
2010-05-24 22:11:39 +08:00
GET_CACHE_SLOT ( opline - > op2 . constant ) ;
1999-04-08 02:10:10 +08:00
break ;
}
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_shell_exec ( znode * result , znode * cmd TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2001-07-28 18:51:54 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
switch ( cmd - > op_type ) {
2008-07-26 23:30:28 +08:00
case IS_CONST :
1999-04-08 02:10:10 +08:00
case IS_TMP_VAR :
opline - > opcode = ZEND_SEND_VAL ;
break ;
default :
opline - > opcode = ZEND_SEND_VAR ;
break ;
}
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op1 , cmd ) ;
2013-05-29 15:12:43 +08:00
opline - > op2 . opline_num = 1 ;
1999-06-09 02:33:31 +08:00
opline - > extended_value = ZEND_DO_FCALL ;
1999-04-08 02:10:10 +08:00
SET_UNUSED ( opline - > op2 ) ;
2001-08-30 23:31:35 +08:00
/* FIXME: exception support not added to this op2 */
2001-07-28 18:51:54 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
opline - > opcode = ZEND_DO_FCALL ;
2010-04-20 18:57:45 +08:00
opline - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
opline - > result_type = IS_VAR ;
2014-02-10 14:04:30 +08:00
LITERAL_STR ( opline - > op1 , STR_INIT ( " shell_exec " , sizeof ( " shell_exec " ) - 1 , 0 ) ) ;
2010-04-20 18:57:45 +08:00
opline - > op1_type = IS_CONST ;
2010-05-24 22:11:39 +08:00
GET_CACHE_SLOT ( opline - > op1 . constant ) ;
1999-06-01 02:33:12 +08:00
opline - > extended_value = 1 ;
1999-04-08 02:10:10 +08:00
SET_UNUSED ( opline - > op2 ) ;
2013-04-20 15:23:49 +08:00
opline - > op2 . num = CG ( context ) . nested_calls ;
2010-04-20 18:57:45 +08:00
GET_NODE ( result , opline - > result ) ;
2012-11-30 17:39:23 +08:00
if ( CG ( context ) . nested_calls + 1 > CG ( active_op_array ) - > nested_calls ) {
CG ( active_op_array ) - > nested_calls = CG ( context ) . nested_calls + 1 ;
}
if ( CG ( context ) . used_stack + 2 > CG ( active_op_array ) - > used_stack ) {
CG ( active_op_array ) - > used_stack = CG ( context ) . used_stack + 2 ;
}
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_init_array ( znode * result , znode * expr , znode * offset , zend_bool is_ref TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2014-04-22 23:54:34 +08:00
int op_num = get_next_op_number ( CG ( active_op_array ) ) ;
2001-07-28 18:51:54 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
2014-04-22 23:54:34 +08:00
result - > u . op . opline_num = op_num ;
1999-04-08 02:10:10 +08:00
opline - > opcode = ZEND_INIT_ARRAY ;
2010-04-20 18:57:45 +08:00
opline - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
opline - > result_type = IS_TMP_VAR ;
2014-04-23 03:33:49 +08:00
opline - > extended_value = is_ref ; /* extval = size << 2 | not_packed << 1 | is_ref */
2014-04-22 23:54:34 +08:00
1999-04-08 02:10:10 +08:00
if ( expr ) {
2014-04-23 06:47:41 +08:00
opline - > extended_value + = 1 < < ZEND_ARRAY_SIZE_SHIFT ; /* increment size */
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op1 , expr ) ;
1999-04-08 02:10:10 +08:00
if ( offset ) {
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op2 , offset ) ;
if ( opline - > op2_type = = IS_CONST & & Z_TYPE ( CONSTANT ( opline - > op2 . constant ) ) = = IS_STRING ) {
2010-10-05 19:28:56 +08:00
ulong index ;
2010-04-20 18:57:45 +08:00
2014-04-23 06:47:41 +08:00
opline - > extended_value | = ZEND_ARRAY_NOT_PACKED ;
2014-06-03 17:10:42 +08:00
if ( ZEND_HANDLE_NUMERIC ( Z_STR ( CONSTANT ( opline - > op2 . constant ) ) , index ) ) {
2010-04-20 18:57:45 +08:00
zval_dtor ( & CONSTANT ( opline - > op2 . constant ) ) ;
2013-01-28 10:02:51 +08:00
ZVAL_LONG ( & CONSTANT ( opline - > op2 . constant ) , index ) ;
2010-04-20 18:57:45 +08:00
}
}
1999-04-08 02:10:10 +08:00
} else {
SET_UNUSED ( opline - > op2 ) ;
}
} else {
SET_UNUSED ( opline - > op1 ) ;
SET_UNUSED ( opline - > op2 ) ;
}
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_add_array_element ( znode * result , znode * expr , znode * offset , zend_bool is_ref TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2001-07-28 18:51:54 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
2014-04-22 23:54:34 +08:00
zend_op * init_opline = & CG ( active_op_array ) - > opcodes [ result - > u . op . opline_num ] ;
2014-04-23 06:47:41 +08:00
init_opline - > extended_value + = 1 < < ZEND_ARRAY_SIZE_SHIFT ; /* increment size */
1999-04-08 02:10:10 +08:00
opline - > opcode = ZEND_ADD_ARRAY_ELEMENT ;
2014-04-22 23:54:34 +08:00
COPY_NODE ( opline - > result , init_opline - > result ) ;
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op1 , expr ) ;
1999-04-08 02:10:10 +08:00
if ( offset ) {
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op2 , offset ) ;
if ( opline - > op2_type = = IS_CONST & & Z_TYPE ( CONSTANT ( opline - > op2 . constant ) ) = = IS_STRING ) {
2010-10-05 19:28:56 +08:00
ulong index ;
2010-04-20 18:57:45 +08:00
2014-04-23 06:47:41 +08:00
init_opline - > extended_value | = ZEND_ARRAY_NOT_PACKED ;
2014-06-03 17:10:42 +08:00
if ( ZEND_HANDLE_NUMERIC ( Z_STR ( CONSTANT ( opline - > op2 . constant ) ) , index ) ) {
2010-04-20 18:57:45 +08:00
zval_dtor ( & CONSTANT ( opline - > op2 . constant ) ) ;
2013-01-28 10:02:51 +08:00
ZVAL_LONG ( & CONSTANT ( opline - > op2 . constant ) , index ) ;
2010-04-20 18:57:45 +08:00
}
}
1999-04-08 02:10:10 +08:00
} else {
SET_UNUSED ( opline - > op2 ) ;
}
1999-10-01 18:00:05 +08:00
opline - > extended_value = is_ref ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-04-22 23:54:34 +08:00
void zend_do_end_array ( znode * result , const znode * array_node TSRMLS_DC ) /* { { { */
{
2014-05-29 22:21:56 +08:00
int next_op_num = get_next_op_number ( CG ( active_op_array ) ) ;
2014-04-22 23:54:34 +08:00
zend_op * init_opline = & CG ( active_op_array ) - > opcodes [ array_node - > u . op . opline_num ] ;
2014-05-29 22:21:56 +08:00
zend_op * opline ;
int i ;
int constant_array = 0 ;
zval array ;
/* check if constructed array consists only from constants */
if ( ( init_opline - > op1_type & ( IS_UNUSED | IS_CONST ) ) & &
( init_opline - > op2_type & ( IS_UNUSED | IS_CONST ) ) ) {
if ( next_op_num = = array_node - > u . op . opline_num + 1 ) {
constant_array = 1 ;
} else if ( ( init_opline - > extended_value > > ZEND_ARRAY_SIZE_SHIFT ) = = next_op_num - array_node - > u . op . opline_num ) {
opline = init_opline + 1 ;
i = next_op_num - array_node - > u . op . opline_num - 1 ;
while ( i > 0 ) {
if ( opline - > opcode ! = ZEND_ADD_ARRAY_ELEMENT | |
opline - > op1_type ! = IS_CONST | |
! ( opline - > op2_type & ( IS_UNUSED | IS_CONST ) ) ) {
break ;
}
opline + + ;
i - - ;
}
if ( i = = 0 ) {
constant_array = 1 ;
}
}
}
if ( constant_array ) {
/* try to construct constant array */
zend_uint size ;
long num ;
zend_string * str ;
if ( init_opline - > op1_type ! = IS_UNUSED ) {
size = init_opline - > extended_value > > ZEND_ARRAY_SIZE_SHIFT ;
} else {
size = 0 ;
}
ZVAL_NEW_ARR ( & array ) ;
zend_hash_init ( Z_ARRVAL ( array ) , size , NULL , ZVAL_PTR_DTOR , 0 ) ;
if ( init_opline - > op1_type ! = IS_UNUSED ) {
/* Explicitly initialize array as not-packed if flag is set */
if ( init_opline - > extended_value & ZEND_ARRAY_NOT_PACKED ) {
zend_hash_real_init ( Z_ARRVAL ( array ) , 0 ) ;
}
opline = init_opline ;
i = next_op_num - array_node - > u . op . opline_num ;
while ( i > 0 & & constant_array ) {
if ( opline - > op2_type = = IS_CONST ) {
switch ( Z_TYPE ( CONSTANT ( opline - > op2 . constant ) ) ) {
case IS_LONG :
num = Z_LVAL ( CONSTANT ( opline - > op2 . constant ) ) ;
num_index :
zend_hash_index_update ( Z_ARRVAL ( array ) , num , & CONSTANT ( opline - > op1 . constant ) ) ;
if ( Z_REFCOUNTED ( CONSTANT ( opline - > op1 . constant ) ) ) Z_ADDREF ( CONSTANT ( opline - > op1 . constant ) ) ;
break ;
case IS_STRING :
str = Z_STR ( CONSTANT ( opline - > op2 . constant ) ) ;
str_index :
zend_hash_update ( Z_ARRVAL ( array ) , str , & CONSTANT ( opline - > op1 . constant ) ) ;
if ( Z_REFCOUNTED ( CONSTANT ( opline - > op1 . constant ) ) ) Z_ADDREF ( CONSTANT ( opline - > op1 . constant ) ) ;
break ;
case IS_DOUBLE :
num = zend_dval_to_lval ( Z_DVAL ( CONSTANT ( opline - > op2 . constant ) ) ) ;
goto num_index ;
case IS_FALSE :
num = 0 ;
goto num_index ;
case IS_TRUE :
num = 1 ;
goto num_index ;
case IS_NULL :
str = STR_EMPTY_ALLOC ( ) ;
goto str_index ;
default :
constant_array = 0 ;
break ;
}
} else {
zend_hash_next_index_insert ( Z_ARRVAL ( array ) , & CONSTANT ( opline - > op1 . constant ) ) ;
if ( Z_REFCOUNTED ( CONSTANT ( opline - > op1 . constant ) ) ) Z_ADDREF ( CONSTANT ( opline - > op1 . constant ) ) ;
}
opline + + ;
i - - ;
}
if ( ! constant_array ) {
zval_dtor ( & array ) ;
}
}
}
if ( constant_array ) {
/* remove run-time array construction and use constant array instead */
opline = & CG ( active_op_array ) - > opcodes [ next_op_num - 1 ] ;
while ( opline ! = init_opline ) {
if ( opline - > op2_type = = IS_CONST ) {
zend_del_literal ( CG ( active_op_array ) , opline - > op2 . constant ) ;
}
zend_del_literal ( CG ( active_op_array ) , opline - > op1 . constant ) ;
opline - - ;
}
if ( opline - > op2_type = = IS_CONST ) {
zend_del_literal ( CG ( active_op_array ) , opline - > op2 . constant ) ;
}
if ( opline - > op1_type = = IS_CONST ) {
zend_del_literal ( CG ( active_op_array ) , opline - > op1 . constant ) ;
}
CG ( active_op_array ) - > last = array_node - > u . op . opline_num ;
zend_make_immutable_array ( & array TSRMLS_CC ) ;
result - > op_type = IS_CONST ;
ZVAL_COPY_VALUE ( & result - > u . constant , & array ) ;
} else {
GET_NODE ( result , init_opline - > result ) ;
}
2014-04-22 23:54:34 +08:00
}
/* }}} */
2009-07-27 22:11:53 +08:00
void zend_do_add_list_element ( const znode * element TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
list_llist_element lle ;
1999-05-23 00:10:51 +08:00
if ( element ) {
2002-03-18 03:13:46 +08:00
zend_check_writable_variable ( element ) ;
1999-04-08 02:10:10 +08:00
lle . var = * element ;
zend_llist_copy ( & lle . dimensions , & CG ( dimension_llist ) ) ;
2000-02-06 04:19:46 +08:00
zend_llist_prepend_element ( & CG ( list_llist ) , & lle ) ;
1999-04-08 02:10:10 +08:00
}
( * ( ( int * ) CG ( dimension_llist ) . tail - > data ) ) + + ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_new_list_begin ( TSRMLS_D ) /* { { { */
1999-04-08 02:10:10 +08:00
{
int current_dimension = 0 ;
zend_llist_add_element ( & CG ( dimension_llist ) , & current_dimension ) ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_new_list_end ( TSRMLS_D ) /* { { { */
1999-04-08 02:10:10 +08:00
{
zend_llist_remove_tail ( & CG ( dimension_llist ) ) ;
( * ( ( int * ) CG ( dimension_llist ) . tail - > data ) ) + + ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_list_init ( TSRMLS_D ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2014-05-01 02:28:02 +08:00
zend_stack_push ( & CG ( list_stack ) , & CG ( list_llist ) ) ;
zend_stack_push ( & CG ( list_stack ) , & CG ( dimension_llist ) ) ;
1999-04-08 02:10:10 +08:00
zend_llist_init ( & CG ( list_llist ) , sizeof ( list_llist_element ) , NULL , 0 ) ;
zend_llist_init ( & CG ( dimension_llist ) , sizeof ( int ) , NULL , 0 ) ;
2001-07-28 18:51:54 +08:00
zend_do_new_list_begin ( TSRMLS_C ) ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_list_end ( znode * result , znode * expr TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
zend_llist_element * le ;
zend_llist_element * dimension ;
zend_op * opline ;
znode last_container ;
le = CG ( list_llist ) . head ;
while ( le ) {
zend_llist * tmp_dimension_llist = & ( ( list_llist_element * ) le - > data ) - > dimensions ;
dimension = tmp_dimension_llist - > head ;
while ( dimension ) {
2001-07-28 18:51:54 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
if ( dimension = = tmp_dimension_llist - > head ) { /* first */
last_container = * expr ;
2002-11-30 19:20:25 +08:00
switch ( expr - > op_type ) {
1999-04-08 02:10:10 +08:00
case IS_VAR :
2004-10-05 03:54:35 +08:00
case IS_CV :
1999-04-08 02:10:10 +08:00
opline - > opcode = ZEND_FETCH_DIM_R ;
break ;
case IS_TMP_VAR :
2000-10-19 17:36:53 +08:00
opline - > opcode = ZEND_FETCH_DIM_TMP_VAR ;
break ;
1999-04-08 02:10:10 +08:00
case IS_CONST : /* fetch_dim_tmp_var will handle this bogus fetch */
2000-10-19 17:36:53 +08:00
zval_copy_ctor ( & expr - > u . constant ) ;
1999-04-08 02:10:10 +08:00
opline - > opcode = ZEND_FETCH_DIM_TMP_VAR ;
break ;
}
2010-04-20 18:57:45 +08:00
opline - > extended_value | = ZEND_FETCH_ADD_LOCK ;
1999-04-08 02:10:10 +08:00
} else {
opline - > opcode = ZEND_FETCH_DIM_R ;
}
2010-04-20 18:57:45 +08:00
opline - > result_type = IS_VAR ;
opline - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
SET_NODE ( opline - > op1 , & last_container ) ;
opline - > op2_type = IS_CONST ;
LITERAL_LONG ( opline - > op2 , * ( ( int * ) dimension - > data ) ) ;
GET_NODE ( & last_container , opline - > result ) ;
1999-04-08 02:10:10 +08:00
dimension = dimension - > next ;
}
( ( list_llist_element * ) le - > data ) - > value = last_container ;
zend_llist_destroy ( & ( ( list_llist_element * ) le - > data ) - > dimensions ) ;
2001-07-28 18:51:54 +08:00
zend_do_assign ( result , & ( ( list_llist_element * ) le - > data ) - > var , & ( ( list_llist_element * ) le - > data ) - > value TSRMLS_CC ) ;
2005-06-03 21:57:26 +08:00
zend_do_free ( result TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
le = le - > next ;
}
zend_llist_destroy ( & CG ( dimension_llist ) ) ;
zend_llist_destroy ( & CG ( list_llist ) ) ;
* result = * expr ;
2001-07-16 23:48:31 +08:00
{
zend_llist * p ;
/* restore previous lists */
2014-05-01 02:48:02 +08:00
p = zend_stack_top ( & CG ( list_stack ) ) ;
2001-07-16 23:48:31 +08:00
CG ( dimension_llist ) = * p ;
zend_stack_del_top ( & CG ( list_stack ) ) ;
2014-05-01 02:48:02 +08:00
p = zend_stack_top ( & CG ( list_stack ) ) ;
2001-07-16 23:48:31 +08:00
CG ( list_llist ) = * p ;
zend_stack_del_top ( & CG ( list_stack ) ) ;
}
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
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
void zend_init_list ( void * result , void * item TSRMLS_DC ) /* { { { */
{
void * * list = emalloc ( sizeof ( void * ) * 2 ) ;
list [ 0 ] = item ;
list [ 1 ] = NULL ;
* ( void * * ) result = list ;
}
/* }}} */
void zend_add_to_list ( void * result , void * item TSRMLS_DC ) /* { { { */
{
void * * list = * ( void * * ) result ;
size_t n = 0 ;
2012-12-25 14:23:08 +08:00
if ( list ) {
while ( list [ n ] ) {
n + + ;
}
}
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
list = erealloc ( list , sizeof ( void * ) * ( n + 2 ) ) ;
list [ n ] = item ;
list [ n + 1 ] = NULL ;
* ( void * * ) result = list ;
}
/* }}} */
2014-04-22 22:52:59 +08:00
void zend_do_fetch_static_variable ( znode * varname , znode * static_assignment , int fetch_type TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2014-02-10 14:04:30 +08:00
zval tmp ;
2003-01-20 01:25:39 +08:00
zend_op * opline ;
znode lval ;
znode result ;
1999-04-08 02:10:10 +08:00
2002-11-30 19:20:25 +08:00
if ( static_assignment ) {
2014-02-10 14:04:30 +08:00
ZVAL_COPY_VALUE ( & tmp , & static_assignment - > u . constant ) ;
2002-11-11 01:50:27 +08:00
} else {
2014-02-10 14:04:30 +08:00
ZVAL_NULL ( & tmp ) ;
2014-04-03 19:26:23 +08:00
Z_CONST_FLAGS ( tmp ) = 0 ;
2002-11-11 01:50:27 +08:00
}
if ( ! CG ( active_op_array ) - > static_variables ) {
2010-07-06 19:40:17 +08:00
if ( CG ( active_op_array ) - > scope ) {
CG ( active_op_array ) - > scope - > ce_flags | = ZEND_HAS_STATIC_IN_METHODS ;
}
2002-11-11 01:50:27 +08:00
ALLOC_HASHTABLE ( CG ( active_op_array ) - > static_variables ) ;
2014-04-21 22:25:34 +08:00
zend_hash_init ( CG ( active_op_array ) - > static_variables , 8 , NULL , ZVAL_PTR_DTOR , 0 ) ;
1999-04-08 02:10:10 +08:00
}
2014-02-10 14:04:30 +08:00
zend_hash_update ( CG ( active_op_array ) - > static_variables , Z_STR ( varname - > u . constant ) , & tmp ) ;
2003-01-20 01:25:39 +08:00
2008-01-24 01:55:55 +08:00
if ( varname - > op_type = = IS_CONST ) {
if ( Z_TYPE ( varname - > u . constant ) ! = IS_STRING ) {
convert_to_string ( & varname - > u . constant ) ;
}
}
2003-01-20 01:25:39 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
2008-07-14 17:49:03 +08:00
opline - > opcode = ( fetch_type = = ZEND_FETCH_LEXICAL ) ? ZEND_FETCH_R : ZEND_FETCH_W ; /* the default mode must be Write, since fetch_simple_variable() is used to define function arguments */
2010-04-20 18:57:45 +08:00
opline - > result_type = IS_VAR ;
opline - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
SET_NODE ( opline - > op1 , varname ) ;
2003-01-20 01:25:39 +08:00
SET_UNUSED ( opline - > op2 ) ;
2010-04-20 18:57:45 +08:00
opline - > extended_value = ZEND_FETCH_STATIC ;
GET_NODE ( & result , opline - > result ) ;
2003-01-20 01:25:39 +08:00
if ( varname - > op_type = = IS_CONST ) {
zval_copy_ctor ( & varname - > u . constant ) ;
}
fetch_simple_variable ( & lval , varname , 0 TSRMLS_CC ) ; /* Relies on the fact that the default fetch is BP_VAR_W */
2008-07-14 17:49:03 +08:00
if ( fetch_type = = ZEND_FETCH_LEXICAL ) {
znode dummy ;
zend_do_begin_variable_parse ( TSRMLS_C ) ;
zend_do_assign ( & dummy , & lval , & result TSRMLS_CC ) ;
zend_do_free ( & dummy TSRMLS_CC ) ;
} else {
zend_do_assign_ref ( NULL , & lval , & result TSRMLS_CC ) ;
}
2010-04-20 18:57:45 +08:00
CG ( active_op_array ) - > opcodes [ CG ( active_op_array ) - > last - 1 ] . result_type | = EXT_TYPE_UNUSED ;
2002-11-11 01:50:27 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_fetch_lexical_variable ( znode * varname , zend_bool is_ref TSRMLS_DC ) /* { { { */
2008-07-14 17:49:03 +08:00
{
znode value ;
if ( Z_STRLEN ( varname - > u . constant ) = = sizeof ( " this " ) - 1 & &
memcmp ( Z_STRVAL ( varname - > u . constant ) , " this " , sizeof ( " this " ) - 1 ) = = 0 ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use $this as lexical variable " ) ;
2008-07-14 17:49:03 +08:00
return ;
}
value . op_type = IS_CONST ;
ZVAL_NULL ( & value . u . constant ) ;
2014-04-03 19:26:23 +08:00
Z_CONST_FLAGS ( value . u . constant ) = is_ref ? IS_LEXICAL_REF : IS_LEXICAL_VAR ;
2008-07-14 17:49:03 +08:00
zend_do_fetch_static_variable ( varname , & value , is_ref ? ZEND_FETCH_STATIC : ZEND_FETCH_LEXICAL TSRMLS_CC ) ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
2008-07-14 17:49:03 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_fetch_global_variable ( znode * varname , const znode * static_assignment , int fetch_type TSRMLS_DC ) /* { { { */
2002-11-11 01:50:27 +08:00
{
zend_op * opline ;
znode lval ;
znode result ;
1999-04-08 02:10:10 +08:00
2008-01-24 01:55:55 +08:00
if ( varname - > op_type = = IS_CONST ) {
if ( Z_TYPE ( varname - > u . constant ) ! = IS_STRING ) {
convert_to_string ( & varname - > u . constant ) ;
}
}
2002-11-11 01:50:27 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
2014-06-06 19:04:30 +08:00
if ( varname - > op_type = = IS_CONST & &
! zend_is_auto_global ( Z_STR ( varname - > u . constant ) TSRMLS_CC ) & &
! ( Z_STRLEN ( varname - > u . constant ) = = ( sizeof ( " this " ) - 1 ) & &
! memcmp ( Z_STRVAL ( varname - > u . constant ) , " this " , sizeof ( " this " ) - 1 ) ) ) {
opline - > opcode = ZEND_BIND_GLOBAL ;
SET_NODE ( opline - > op2 , varname ) ;
opline - > op1_type = IS_CV ;
1999-04-08 02:10:10 +08:00
zval_copy_ctor ( & varname - > u . constant ) ;
2014-06-06 19:04:30 +08:00
opline - > op1 . var = lookup_cv ( CG ( active_op_array ) , Z_STR ( varname - > u . constant ) TSRMLS_CC ) ;
} else {
opline - > opcode = ZEND_FETCH_W ; /* the default mode must be Write, since fetch_simple_variable() is used to define function arguments */
opline - > result_type = IS_VAR ;
opline - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
SET_NODE ( opline - > op1 , varname ) ;
SET_UNUSED ( opline - > op2 ) ;
opline - > extended_value = fetch_type ;
GET_NODE ( & result , opline - > result ) ;
1999-04-08 02:10:10 +08:00
2014-06-06 19:04:30 +08:00
if ( varname - > op_type = = IS_CONST ) {
zval_copy_ctor ( & varname - > u . constant ) ;
}
fetch_simple_variable ( & lval , varname , 0 TSRMLS_CC ) ; /* Relies on the fact that the default fetch is BP_VAR_W */
zend_do_assign_ref ( NULL , & lval , & result TSRMLS_CC ) ;
CG ( active_op_array ) - > opcodes [ CG ( active_op_array ) - > last - 1 ] . result_type | = EXT_TYPE_UNUSED ;
}
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_cast ( znode * result , znode * expr , int type TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2001-07-28 18:51:54 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
opline - > opcode = ZEND_CAST ;
2014-04-17 04:39:01 +08:00
opline - > result_type = IS_VAR ;
2010-04-20 18:57:45 +08:00
opline - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
SET_NODE ( opline - > op1 , expr ) ;
1999-04-08 02:10:10 +08:00
SET_UNUSED ( opline - > op2 ) ;
2000-05-04 01:56:44 +08:00
opline - > extended_value = type ;
2010-04-20 18:57:45 +08:00
GET_NODE ( result , opline - > result ) ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_include_or_eval ( int type , znode * result , znode * op1 TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2001-07-28 18:51:54 +08:00
zend_do_extended_fcall_begin ( TSRMLS_C ) ;
2000-09-11 23:15:57 +08:00
{
2001-07-28 18:51:54 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
2000-09-11 23:15:57 +08:00
opline - > opcode = ZEND_INCLUDE_OR_EVAL ;
2010-04-20 18:57:45 +08:00
opline - > result_type = IS_VAR ;
opline - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
SET_NODE ( opline - > op1 , op1 ) ;
2000-09-11 23:15:57 +08:00
SET_UNUSED ( opline - > op2 ) ;
2010-04-20 18:57:45 +08:00
opline - > extended_value = type ;
GET_NODE ( result , opline - > result ) ;
1999-12-23 23:03:25 +08:00
}
2001-07-28 18:51:54 +08:00
zend_do_extended_fcall_end ( TSRMLS_C ) ;
1999-12-23 23:03:25 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-12-23 23:03:25 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_indirect_references ( znode * result , const znode * num_references , znode * variable TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
int i ;
2008-05-07 20:04:39 +08:00
zend_do_end_variable_parse ( variable , BP_VAR_R , 0 TSRMLS_CC ) ;
2013-09-13 21:07:47 +08:00
for ( i = 1 ; i < Z_LVAL ( num_references - > u . constant ) ; i + + ) {
2001-07-28 18:51:54 +08:00
fetch_simple_variable_ex ( result , variable , 0 , ZEND_FETCH_R TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
* variable = * result ;
}
2001-07-28 18:51:54 +08:00
zend_do_begin_variable_parse ( TSRMLS_C ) ;
fetch_simple_variable ( result , variable , 1 TSRMLS_CC ) ;
2010-12-01 21:33:49 +08:00
/* there is a chance someone is accessing $this */
if ( CG ( active_op_array ) - > scope & & CG ( active_op_array ) - > this_var = = - 1 ) {
2014-02-10 14:04:30 +08:00
zend_string * key = STR_INIT ( " this " , sizeof ( " this " ) - 1 , 0 ) ;
CG ( active_op_array ) - > this_var = lookup_cv ( CG ( active_op_array ) , key TSRMLS_CC ) ;
2010-12-01 21:33:49 +08:00
}
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_unset ( znode * variable TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
zend_op * last_op ;
2002-03-18 03:13:46 +08:00
zend_check_writable_variable ( variable ) ;
2004-10-05 03:54:35 +08:00
if ( variable - > op_type = = IS_CV ) {
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
opline - > opcode = ZEND_UNSET_VAR ;
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op1 , variable ) ;
2004-10-05 03:54:35 +08:00
SET_UNUSED ( opline - > op2 ) ;
SET_UNUSED ( opline - > result ) ;
2010-04-20 18:57:45 +08:00
opline - > extended_value = ZEND_FETCH_LOCAL | ZEND_QUICK_SET ;
2004-10-05 03:54:35 +08:00
} else {
last_op = & CG ( active_op_array ) - > opcodes [ get_next_op_number ( CG ( active_op_array ) ) - 1 ] ;
1999-04-08 02:10:10 +08:00
2004-10-05 03:54:35 +08:00
switch ( last_op - > opcode ) {
case ZEND_FETCH_UNSET :
last_op - > opcode = ZEND_UNSET_VAR ;
2010-07-29 17:46:59 +08:00
SET_UNUSED ( last_op - > result ) ;
2004-10-05 03:54:35 +08:00
break ;
case ZEND_FETCH_DIM_UNSET :
2005-06-16 20:17:39 +08:00
last_op - > opcode = ZEND_UNSET_DIM ;
2010-07-29 17:46:59 +08:00
SET_UNUSED ( last_op - > result ) ;
2004-10-05 03:54:35 +08:00
break ;
case ZEND_FETCH_OBJ_UNSET :
2005-06-16 20:17:39 +08:00
last_op - > opcode = ZEND_UNSET_OBJ ;
2010-07-29 17:46:59 +08:00
SET_UNUSED ( last_op - > result ) ;
2004-10-05 03:54:35 +08:00
break ;
1999-04-08 02:10:10 +08:00
2004-10-05 03:54:35 +08:00
}
2006-05-10 07:53:23 +08:00
}
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_isset_or_isempty ( int type , znode * result , znode * variable TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2002-02-05 03:29:56 +08:00
zend_op * last_op ;
1999-04-08 02:10:10 +08:00
2008-05-07 20:04:39 +08:00
zend_do_end_variable_parse ( variable , BP_VAR_IS , 0 TSRMLS_CC ) ;
2001-12-26 22:46:18 +08:00
2012-04-12 17:54:52 +08:00
if ( zend_is_function_or_method_call ( variable ) ) {
if ( type = = ZEND_ISEMPTY ) {
/* empty(func()) can be transformed to !func() */
zend_do_unary_op ( ZEND_BOOL_NOT , result , variable TSRMLS_CC ) ;
} else {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use isset() on the result of a function call (you can use \" null !== func() \" instead) " ) ;
2012-04-12 17:54:52 +08:00
}
return ;
}
2006-05-10 07:53:23 +08:00
2004-10-05 03:54:35 +08:00
if ( variable - > op_type = = IS_CV ) {
last_op = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
last_op - > opcode = ZEND_ISSET_ISEMPTY_VAR ;
2010-04-20 18:57:45 +08:00
SET_NODE ( last_op - > op1 , variable ) ;
2004-10-05 03:54:35 +08:00
SET_UNUSED ( last_op - > op2 ) ;
2010-04-20 18:57:45 +08:00
last_op - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
last_op - > extended_value = ZEND_FETCH_LOCAL | ZEND_QUICK_SET ;
2004-10-05 03:54:35 +08:00
} else {
last_op = & CG ( active_op_array ) - > opcodes [ get_next_op_number ( CG ( active_op_array ) ) - 1 ] ;
2006-05-10 07:53:23 +08:00
2004-10-05 03:54:35 +08:00
switch ( last_op - > opcode ) {
case ZEND_FETCH_IS :
last_op - > opcode = ZEND_ISSET_ISEMPTY_VAR ;
break ;
case ZEND_FETCH_DIM_IS :
last_op - > opcode = ZEND_ISSET_ISEMPTY_DIM_OBJ ;
break ;
case ZEND_FETCH_OBJ_IS :
last_op - > opcode = ZEND_ISSET_ISEMPTY_PROP_OBJ ;
break ;
}
2002-02-05 03:29:56 +08:00
}
2010-04-20 18:57:45 +08:00
last_op - > result_type = IS_TMP_VAR ;
2008-05-12 17:09:05 +08:00
last_op - > extended_value | = type ;
2002-02-05 03:29:56 +08:00
2010-04-20 18:57:45 +08:00
GET_NODE ( result , last_op - > result ) ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_instanceof ( znode * result , znode * expr , znode * class_znode , int type TSRMLS_DC ) /* { { { */
2002-07-30 12:07:15 +08:00
{
2005-09-09 14:48:49 +08:00
int last_op_number = get_next_op_number ( CG ( active_op_array ) ) ;
zend_op * opline ;
2002-07-30 12:07:15 +08:00
2005-09-09 14:48:49 +08:00
if ( last_op_number > 0 ) {
opline = & CG ( active_op_array ) - > opcodes [ last_op_number - 1 ] ;
if ( opline - > opcode = = ZEND_FETCH_CLASS ) {
opline - > extended_value | = ZEND_FETCH_CLASS_NO_AUTOLOAD ;
}
}
2006-12-13 07:25:23 +08:00
if ( expr - > op_type = = IS_CONST ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " instanceof expects an object instance, constant given " ) ;
2006-12-13 07:25:23 +08:00
}
2005-09-09 14:48:49 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
2003-01-15 05:29:23 +08:00
opline - > opcode = ZEND_INSTANCEOF ;
2010-04-20 18:57:45 +08:00
opline - > result_type = IS_TMP_VAR ;
opline - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
SET_NODE ( opline - > op1 , expr ) ;
2002-07-30 12:07:15 +08:00
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op2 , class_znode ) ;
2002-07-30 12:07:15 +08:00
2010-04-20 18:57:45 +08:00
GET_NODE ( result , opline - > result ) ;
2002-07-30 12:07:15 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2002-07-30 12:07:15 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_foreach_begin ( znode * foreach_token , znode * open_brackets_token , znode * array , znode * as_token , int variable TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2001-08-08 23:07:11 +08:00
zend_op * opline ;
zend_bool is_variable ;
2007-01-10 23:58:08 +08:00
zend_op dummy_opline ;
2001-08-08 23:07:11 +08:00
if ( variable ) {
2001-12-26 22:46:18 +08:00
if ( zend_is_function_or_method_call ( array ) ) {
2001-08-08 23:07:11 +08:00
is_variable = 0 ;
} else {
is_variable = 1 ;
}
2007-01-10 23:58:08 +08:00
/* save the location of FETCH_W instruction(s) */
2010-04-20 18:57:45 +08:00
open_brackets_token - > u . op . opline_num = get_next_op_number ( CG ( active_op_array ) ) ;
2008-05-07 20:04:39 +08:00
zend_do_end_variable_parse ( array , BP_VAR_W , 0 TSRMLS_CC ) ;
2001-08-08 23:07:11 +08:00
} else {
is_variable = 0 ;
2010-04-20 18:57:45 +08:00
open_brackets_token - > u . op . opline_num = get_next_op_number ( CG ( active_op_array ) ) ;
2001-08-08 23:07:11 +08:00
}
2005-02-12 06:26:45 +08:00
/* save the location of FE_RESET */
2010-04-20 18:57:45 +08:00
foreach_token - > u . op . opline_num = get_next_op_number ( CG ( active_op_array ) ) ;
2005-02-12 06:26:45 +08:00
2001-08-08 23:07:11 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
/* Preform array reset */
opline - > opcode = ZEND_FE_RESET ;
2010-04-20 18:57:45 +08:00
opline - > result_type = IS_VAR ;
opline - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
SET_NODE ( opline - > op1 , array ) ;
1999-04-08 02:10:10 +08:00
SET_UNUSED ( opline - > op2 ) ;
2006-05-12 05:07:39 +08:00
opline - > extended_value = is_variable ? ZEND_FE_RESET_VARIABLE : 0 ;
1999-04-08 02:10:10 +08:00
2010-04-20 18:57:45 +08:00
COPY_NODE ( dummy_opline . result , opline - > result ) ;
2014-05-01 02:28:02 +08:00
zend_stack_push ( & CG ( foreach_copy_stack ) , ( void * ) & dummy_opline ) ;
2006-05-10 07:53:23 +08:00
2005-02-12 06:26:45 +08:00
/* save the location of FE_FETCH */
2010-04-20 18:57:45 +08:00
as_token - > u . op . opline_num = get_next_op_number ( CG ( active_op_array ) ) ;
2005-02-07 23:22:38 +08:00
2001-07-28 18:51:54 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
opline - > opcode = ZEND_FE_FETCH ;
2010-04-20 18:57:45 +08:00
opline - > result_type = IS_VAR ;
opline - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
COPY_NODE ( opline - > op1 , dummy_opline . result ) ;
2003-07-24 20:38:33 +08:00
opline - > extended_value = 0 ;
1999-04-08 02:10:10 +08:00
SET_UNUSED ( opline - > op2 ) ;
2005-02-08 00:09:54 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
opline - > opcode = ZEND_OP_DATA ;
2014-03-13 21:01:28 +08:00
/* Allocate enough space to keep HashPointer on VM stack */
opline - > op1_type = IS_TMP_VAR ;
opline - > op1 . var = get_temporary_variable ( CG ( active_op_array ) ) ;
if ( sizeof ( HashPointer ) > sizeof ( zval ) ) {
/* Make shure 1 zval is enough for HashPointer (2 must be enough) */
get_temporary_variable ( CG ( active_op_array ) ) ;
}
2005-02-12 06:26:45 +08:00
SET_UNUSED ( opline - > op2 ) ;
SET_UNUSED ( opline - > result ) ;
2005-02-07 23:22:38 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2005-02-07 23:22:38 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_foreach_cont ( znode * foreach_token , const znode * open_brackets_token , const znode * as_token , znode * value , znode * key TSRMLS_DC ) /* { { { */
2005-02-07 23:22:38 +08:00
{
zend_op * opline ;
2005-02-20 18:19:11 +08:00
znode dummy , value_node ;
2005-02-07 23:22:38 +08:00
zend_bool assign_by_ref = 0 ;
1999-04-08 02:10:10 +08:00
2011-07-09 22:35:37 +08:00
opline = & CG ( active_op_array ) - > opcodes [ as_token - > u . op . opline_num ] ;
1999-04-08 02:10:10 +08:00
if ( key - > op_type ! = IS_UNUSED ) {
znode * tmp ;
/* switch between the key and value... */
tmp = key ;
key = value ;
value = tmp ;
2004-08-12 13:41:01 +08:00
/* Mark extended_value in case both key and value are being used */
2005-02-08 00:09:54 +08:00
opline - > extended_value | = ZEND_FE_FETCH_WITH_KEY ;
1999-04-08 02:10:10 +08:00
}
2012-08-26 11:37:05 +08:00
if ( ( key - > op_type ! = IS_UNUSED ) ) {
2012-08-26 12:27:10 +08:00
if ( key - > EA & ZEND_PARSED_REFERENCE_VARIABLE ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Key element cannot be a reference " ) ;
2012-08-26 12:27:10 +08:00
}
if ( key - > EA & ZEND_PARSED_LIST_EXPR ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use list as key element " ) ;
2012-08-26 12:27:10 +08:00
}
2003-07-24 20:38:33 +08:00
}
2005-02-08 00:09:54 +08:00
2010-04-20 18:57:45 +08:00
if ( value - > EA & ZEND_PARSED_REFERENCE_VARIABLE ) {
2003-07-24 20:38:33 +08:00
assign_by_ref = 1 ;
2012-07-22 20:33:25 +08:00
2004-08-12 13:41:01 +08:00
/* Mark extended_value for assign-by-reference */
2005-02-08 00:09:54 +08:00
opline - > extended_value | = ZEND_FE_FETCH_BYREF ;
2010-04-20 18:57:45 +08:00
CG ( active_op_array ) - > opcodes [ foreach_token - > u . op . opline_num ] . extended_value | = ZEND_FE_RESET_REFERENCE ;
2007-01-10 23:58:08 +08:00
} else {
2010-04-20 18:57:45 +08:00
zend_op * fetch = & CG ( active_op_array ) - > opcodes [ foreach_token - > u . op . opline_num ] ;
zend_op * end = & CG ( active_op_array ) - > opcodes [ open_brackets_token - > u . op . opline_num ] ;
2007-01-10 23:58:08 +08:00
/* Change "write context" into "read context" */
fetch - > extended_value = 0 ; /* reset ZEND_FE_RESET_VARIABLE */
while ( fetch ! = end ) {
2007-05-11 17:39:36 +08:00
- - fetch ;
2010-04-20 18:57:45 +08:00
if ( fetch - > opcode = = ZEND_FETCH_DIM_W & & fetch - > op2_type = = IS_UNUSED ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use [] for reading " ) ;
2007-05-11 17:39:36 +08:00
}
2010-08-25 17:14:36 +08:00
if ( fetch - > opcode = = ZEND_SEPARATE ) {
MAKE_NOP ( fetch ) ;
} else {
fetch - > opcode - = 3 ; /* FETCH_W -> FETCH_R */
}
2007-01-10 23:58:08 +08:00
}
1999-04-08 02:10:10 +08:00
}
2010-04-20 18:57:45 +08:00
GET_NODE ( & value_node , opline - > result ) ;
2006-05-12 05:07:39 +08:00
2012-08-25 22:23:14 +08:00
if ( value - > EA & ZEND_PARSED_LIST_EXPR ) {
2012-08-26 13:05:33 +08:00
if ( ! CG ( list_llist ) . head ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use empty list " ) ;
2012-08-26 13:05:33 +08:00
}
2012-08-25 22:23:14 +08:00
zend_do_list_end ( & dummy , & value_node TSRMLS_CC ) ;
2005-02-08 00:09:54 +08:00
zend_do_free ( & dummy TSRMLS_CC ) ;
2012-08-25 22:23:14 +08:00
} else {
if ( assign_by_ref ) {
zend_do_end_variable_parse ( value , BP_VAR_W , 0 TSRMLS_CC ) ;
/* Mark FE_FETCH as IS_VAR as it holds the data directly as a value */
zend_do_assign_ref ( NULL , value , & value_node TSRMLS_CC ) ;
} else {
zend_do_assign ( & dummy , value , & value_node TSRMLS_CC ) ;
zend_do_free ( & dummy TSRMLS_CC ) ;
}
2003-07-24 20:38:33 +08:00
}
2005-02-08 00:09:54 +08:00
1999-04-08 02:10:10 +08:00
if ( key - > op_type ! = IS_UNUSED ) {
2005-02-20 18:19:11 +08:00
znode key_node ;
2010-04-20 18:57:45 +08:00
opline = & CG ( active_op_array ) - > opcodes [ as_token - > u . op . opline_num + 1 ] ;
opline - > result_type = IS_TMP_VAR ;
opline - > result . opline_num = get_temporary_variable ( CG ( active_op_array ) ) ;
GET_NODE ( & key_node , opline - > result ) ;
2005-02-08 00:09:54 +08:00
2005-02-20 18:19:11 +08:00
zend_do_assign ( & dummy , key , & key_node TSRMLS_CC ) ;
2005-02-08 00:09:54 +08:00
zend_do_free ( & dummy TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
}
2001-07-28 18:51:54 +08:00
do_begin_loop ( TSRMLS_C ) ;
1999-04-08 02:10:10 +08:00
INC_BPC ( CG ( active_op_array ) ) ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_foreach_end ( const znode * foreach_token , const znode * as_token TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2004-03-05 21:04:21 +08:00
zend_op * container_ptr ;
2001-07-28 18:51:54 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
opline - > opcode = ZEND_JMP ;
2010-04-20 18:57:45 +08:00
opline - > op1 . opline_num = as_token - > u . op . opline_num ;
1999-10-28 23:53:31 +08:00
SET_UNUSED ( opline - > op1 ) ;
1999-04-08 02:10:10 +08:00
SET_UNUSED ( opline - > op2 ) ;
2010-04-20 18:57:45 +08:00
CG ( active_op_array ) - > opcodes [ foreach_token - > u . op . opline_num ] . op2 . opline_num = get_next_op_number ( CG ( active_op_array ) ) ; /* FE_RESET */
CG ( active_op_array ) - > opcodes [ as_token - > u . op . opline_num ] . op2 . opline_num = get_next_op_number ( CG ( active_op_array ) ) ; /* FE_FETCH */
1999-04-08 02:10:10 +08:00
2010-04-20 18:57:45 +08:00
do_end_loop ( as_token - > u . op . opline_num , 1 TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
2014-05-01 02:48:02 +08:00
container_ptr = zend_stack_top ( & CG ( foreach_copy_stack ) ) ;
2004-02-26 01:23:50 +08:00
generate_free_foreach_copy ( container_ptr TSRMLS_CC ) ;
zend_stack_del_top ( & CG ( foreach_copy_stack ) ) ;
1999-04-08 02:10:10 +08:00
DEC_BPC ( CG ( active_op_array ) ) ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_declare_begin ( TSRMLS_D ) /* { { { */
2000-01-25 03:00:30 +08:00
{
2014-05-01 02:28:02 +08:00
zend_stack_push ( & CG ( declare_stack ) , & CG ( declarables ) ) ;
2000-01-25 03:00:30 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2000-01-25 03:00:30 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_declare_stmt ( znode * var , znode * val TSRMLS_DC ) /* { { { */
2000-01-25 03:00:30 +08:00
{
2013-09-13 21:07:47 +08:00
if ( ! zend_binary_strcasecmp ( Z_STRVAL ( var - > u . constant ) , Z_STRLEN ( var - > u . constant ) , " ticks " , sizeof ( " ticks " ) - 1 ) ) {
2000-01-25 03:00:30 +08:00
convert_to_long ( & val - > u . constant ) ;
CG ( declarables ) . ticks = val - > u . constant ;
2013-09-13 21:07:47 +08:00
} else if ( ! zend_binary_strcasecmp ( Z_STRVAL ( var - > u . constant ) , Z_STRLEN ( var - > u . constant ) , " encoding " , sizeof ( " encoding " ) - 1 ) ) {
2014-04-03 19:26:23 +08:00
if ( Z_TYPE ( val - > u . constant ) = = IS_CONSTANT ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use constants as encoding " ) ;
2008-06-29 16:21:35 +08:00
}
/*
* Check that the pragma comes before any opcodes . If the compilation
* got as far as this , the previous portion of the script must have been
* parseable according to the . ini script_encoding setting . We still
* want to tell them to put declare ( ) at the top .
*/
2008-07-25 06:21:41 +08:00
{
2008-06-29 16:21:35 +08:00
int num = CG ( active_op_array ) - > last ;
2008-07-25 06:21:41 +08:00
/* ignore ZEND_EXT_STMT and ZEND_TICKS */
2008-06-29 16:21:35 +08:00
while ( num > 0 & &
( CG ( active_op_array ) - > opcodes [ num - 1 ] . opcode = = ZEND_EXT_STMT | |
CG ( active_op_array ) - > opcodes [ num - 1 ] . opcode = = ZEND_TICKS ) ) {
- - num ;
}
2008-07-25 06:21:41 +08:00
2009-12-13 23:18:58 +08:00
if ( num > 0 ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Encoding declaration pragma must be the very first statement in the script " ) ;
2008-06-29 16:21:35 +08:00
}
2008-07-25 06:21:41 +08:00
}
2008-06-29 16:21:35 +08:00
2010-11-24 13:41:23 +08:00
if ( CG ( multibyte ) ) {
2011-09-13 21:29:35 +08:00
const zend_encoding * new_encoding , * old_encoding ;
2010-11-24 13:41:23 +08:00
zend_encoding_filter old_input_filter ;
CG ( encoding_declared ) = 1 ;
convert_to_string ( & val - > u . constant ) ;
2013-09-13 21:07:47 +08:00
new_encoding = zend_multibyte_fetch_encoding ( Z_STRVAL ( val - > u . constant ) TSRMLS_CC ) ;
2010-11-24 13:41:23 +08:00
if ( ! new_encoding ) {
2013-09-13 21:07:47 +08:00
zend_error ( E_COMPILE_WARNING , " Unsupported encoding [%s] " , Z_STRVAL ( val - > u . constant ) ) ;
2010-11-24 13:41:23 +08:00
} else {
old_input_filter = LANG_SCNG ( input_filter ) ;
old_encoding = LANG_SCNG ( script_encoding ) ;
zend_multibyte_set_filter ( new_encoding TSRMLS_CC ) ;
/* need to re-scan if input filter changed */
if ( old_input_filter ! = LANG_SCNG ( input_filter ) | |
2011-03-06 15:00:30 +08:00
( old_input_filter & & new_encoding ! = old_encoding ) ) {
2010-11-24 13:41:23 +08:00
zend_multibyte_yyinput_again ( old_input_filter , old_encoding TSRMLS_CC ) ;
}
2008-06-29 16:21:35 +08:00
}
2010-12-20 00:36:37 +08:00
} else {
zend_error ( E_COMPILE_WARNING , " declare(encoding=...) ignored because Zend multibyte feature is turned off by settings " ) ;
2008-06-29 16:21:35 +08:00
}
2008-11-12 00:15:53 +08:00
zval_dtor ( & val - > u . constant ) ;
2006-03-27 16:09:18 +08:00
} else {
2013-09-13 21:07:47 +08:00
zend_error ( E_COMPILE_WARNING , " Unsupported declare '%s' " , Z_STRVAL ( var - > u . constant ) ) ;
2006-03-27 16:09:18 +08:00
zval_dtor ( & val - > u . constant ) ;
2000-01-25 03:00:30 +08:00
}
zval_dtor ( & var - > u . constant ) ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
2000-01-25 03:00:30 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_declare_end ( const znode * declare_token TSRMLS_DC ) /* { { { */
2000-01-25 03:00:30 +08:00
{
2014-05-01 02:48:02 +08:00
zend_declarables * declarables = zend_stack_top ( & CG ( declare_stack ) ) ;
2002-07-31 06:19:50 +08:00
/* We should restore if there was more than (current - start) - (ticks?1:0) opcodes */
2010-04-20 18:57:45 +08:00
if ( ( get_next_op_number ( CG ( active_op_array ) ) - declare_token - > u . op . opline_num ) - ( ( Z_LVAL ( CG ( declarables ) . ticks ) ) ? 1 : 0 ) ) {
2002-07-31 06:19:50 +08:00
CG ( declarables ) = * declarables ;
}
2000-01-25 03:00:30 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2000-01-25 03:00:30 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_exit ( znode * result , znode * message TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2001-07-28 18:51:54 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
opline - > opcode = ZEND_EXIT ;
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op1 , message ) ;
1999-04-08 02:10:10 +08:00
SET_UNUSED ( opline - > op2 ) ;
result - > op_type = IS_CONST ;
2014-04-03 19:26:23 +08:00
ZVAL_BOOL ( & result - > u . constant , 1 ) ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_begin_silence ( znode * strudel_token TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2001-07-28 18:51:54 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
opline - > opcode = ZEND_BEGIN_SILENCE ;
2010-04-20 18:57:45 +08:00
opline - > result_type = IS_TMP_VAR ;
opline - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
1999-04-08 02:10:10 +08:00
SET_UNUSED ( opline - > op1 ) ;
SET_UNUSED ( opline - > op2 ) ;
2010-04-20 18:57:45 +08:00
GET_NODE ( strudel_token , opline - > result ) ;
1999-04-08 02:10:10 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_end_silence ( znode * strudel_token TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2001-07-28 18:51:54 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
opline - > opcode = ZEND_END_SILENCE ;
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op1 , strudel_token ) ;
1999-04-08 02:10:10 +08:00
SET_UNUSED ( opline - > op2 ) ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_jmp_set ( znode * value , znode * jmp_token , znode * colon_token TSRMLS_DC ) /* { { { */
2007-11-21 17:41:35 +08:00
{
int op_number = get_next_op_number ( CG ( active_op_array ) ) ;
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
2011-10-19 03:42:42 +08:00
if ( value - > op_type = = IS_VAR | | value - > op_type = = IS_CV ) {
opline - > opcode = ZEND_JMP_SET_VAR ;
opline - > result_type = IS_VAR ;
} else {
opline - > opcode = ZEND_JMP_SET ;
opline - > result_type = IS_TMP_VAR ;
}
2010-04-20 18:57:45 +08:00
opline - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
SET_NODE ( opline - > op1 , value ) ;
2007-11-21 17:41:35 +08:00
SET_UNUSED ( opline - > op2 ) ;
2013-01-28 10:02:51 +08:00
2010-04-20 18:57:45 +08:00
GET_NODE ( colon_token , opline - > result ) ;
2007-11-21 17:41:35 +08:00
2011-12-06 14:44:22 +08:00
jmp_token - > u . op . opline_num = op_number ;
2007-11-21 17:41:35 +08:00
INC_BPC ( CG ( active_op_array ) ) ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
2007-11-21 17:41:35 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_jmp_set_else ( znode * result , znode * false_value , const znode * jmp_token , znode * colon_token TSRMLS_DC ) /* { { { */
2007-11-21 17:41:35 +08:00
{
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > result , colon_token ) ;
2011-10-19 03:42:42 +08:00
if ( colon_token - > op_type = = IS_TMP_VAR ) {
if ( false_value - > op_type = = IS_VAR | | false_value - > op_type = = IS_CV ) {
CG ( active_op_array ) - > opcodes [ jmp_token - > u . op . opline_num ] . opcode = ZEND_JMP_SET_VAR ;
CG ( active_op_array ) - > opcodes [ jmp_token - > u . op . opline_num ] . result_type = IS_VAR ;
opline - > opcode = ZEND_QM_ASSIGN_VAR ;
opline - > result_type = IS_VAR ;
} else {
opline - > opcode = ZEND_QM_ASSIGN ;
}
} else {
opline - > opcode = ZEND_QM_ASSIGN_VAR ;
}
opline - > extended_value = 0 ;
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op1 , false_value ) ;
2007-11-21 17:41:35 +08:00
SET_UNUSED ( opline - > op2 ) ;
2013-01-28 10:02:51 +08:00
2010-04-20 18:57:45 +08:00
GET_NODE ( result , opline - > result ) ;
2007-11-21 17:41:35 +08:00
2010-04-20 18:57:45 +08:00
CG ( active_op_array ) - > opcodes [ jmp_token - > u . op . opline_num ] . op2 . opline_num = get_next_op_number ( CG ( active_op_array ) ) ;
2013-01-28 10:02:51 +08:00
2007-11-21 17:41:35 +08:00
DEC_BPC ( CG ( active_op_array ) ) ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
2007-11-21 17:41:35 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_begin_qm_op ( znode * cond , znode * qm_token TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
int jmpz_op_number = get_next_op_number ( CG ( active_op_array ) ) ;
zend_op * opline ;
2006-05-10 07:53:23 +08:00
2001-07-28 18:51:54 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
opline - > opcode = ZEND_JMPZ ;
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op1 , cond ) ;
1999-04-08 02:10:10 +08:00
SET_UNUSED ( opline - > op2 ) ;
2010-04-20 18:57:45 +08:00
opline - > op2 . opline_num = jmpz_op_number ;
GET_NODE ( qm_token , opline - > op2 ) ;
1999-04-08 02:10:10 +08:00
INC_BPC ( CG ( active_op_array ) ) ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_qm_true ( znode * true_value , znode * qm_token , znode * colon_token TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2001-07-28 18:51:54 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
2010-04-20 18:57:45 +08:00
CG ( active_op_array ) - > opcodes [ qm_token - > u . op . opline_num ] . op2 . opline_num = get_next_op_number ( CG ( active_op_array ) ) + 1 ; /* jmp over the ZEND_JMP */
1999-04-08 02:10:10 +08:00
2011-10-19 03:42:42 +08:00
if ( true_value - > op_type = = IS_VAR | | true_value - > op_type = = IS_CV ) {
opline - > opcode = ZEND_QM_ASSIGN_VAR ;
opline - > result_type = IS_VAR ;
} else {
opline - > opcode = ZEND_QM_ASSIGN ;
opline - > result_type = IS_TMP_VAR ;
}
2010-04-20 18:57:45 +08:00
opline - > result . var = get_temporary_variable ( CG ( active_op_array ) ) ;
SET_NODE ( opline - > op1 , true_value ) ;
1999-04-08 02:10:10 +08:00
SET_UNUSED ( opline - > op2 ) ;
2010-04-20 18:57:45 +08:00
GET_NODE ( qm_token , opline - > result ) ;
colon_token - > u . op . opline_num = get_next_op_number ( CG ( active_op_array ) ) ;
1999-04-08 02:10:10 +08:00
2001-07-28 18:51:54 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
opline - > opcode = ZEND_JMP ;
SET_UNUSED ( opline - > op1 ) ;
SET_UNUSED ( opline - > op2 ) ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-04-22 22:52:59 +08:00
void zend_do_qm_false ( znode * result , znode * false_value , znode * qm_token , const znode * colon_token TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2001-07-28 18:51:54 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > result , qm_token ) ;
2011-10-19 03:42:42 +08:00
if ( qm_token - > op_type = = IS_TMP_VAR ) {
if ( false_value - > op_type = = IS_VAR | | false_value - > op_type = = IS_CV ) {
CG ( active_op_array ) - > opcodes [ colon_token - > u . op . opline_num - 1 ] . opcode = ZEND_QM_ASSIGN_VAR ;
CG ( active_op_array ) - > opcodes [ colon_token - > u . op . opline_num - 1 ] . result_type = IS_VAR ;
opline - > opcode = ZEND_QM_ASSIGN_VAR ;
opline - > result_type = IS_VAR ;
} else {
opline - > opcode = ZEND_QM_ASSIGN ;
}
} else {
opline - > opcode = ZEND_QM_ASSIGN_VAR ;
}
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op1 , false_value ) ;
1999-04-08 02:10:10 +08:00
SET_UNUSED ( opline - > op2 ) ;
2006-05-10 07:53:23 +08:00
2010-04-20 18:57:45 +08:00
CG ( active_op_array ) - > opcodes [ colon_token - > u . op . opline_num ] . op1 . opline_num = get_next_op_number ( CG ( active_op_array ) ) ;
1999-04-08 02:10:10 +08:00
2010-04-20 18:57:45 +08:00
GET_NODE ( result , opline - > result ) ;
1999-04-08 02:10:10 +08:00
DEC_BPC ( CG ( active_op_array ) ) ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_extended_info ( TSRMLS_D ) /* { { { */
1999-04-08 02:10:10 +08:00
{
zend_op * opline ;
2006-05-10 07:53:23 +08:00
2008-03-18 16:36:30 +08:00
if ( ! ( CG ( compiler_options ) & ZEND_COMPILE_EXTENDED_INFO ) ) {
1999-04-08 02:10:10 +08:00
return ;
}
2006-05-10 07:53:23 +08:00
2001-07-28 18:51:54 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
opline - > opcode = ZEND_EXT_STMT ;
SET_UNUSED ( opline - > op1 ) ;
SET_UNUSED ( opline - > op2 ) ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_extended_fcall_begin ( TSRMLS_D ) /* { { { */
1999-04-08 02:10:10 +08:00
{
zend_op * opline ;
2006-05-10 07:53:23 +08:00
2008-03-18 16:36:30 +08:00
if ( ! ( CG ( compiler_options ) & ZEND_COMPILE_EXTENDED_INFO ) ) {
1999-04-08 02:10:10 +08:00
return ;
}
2006-05-10 07:53:23 +08:00
2001-07-28 18:51:54 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
opline - > opcode = ZEND_EXT_FCALL_BEGIN ;
SET_UNUSED ( opline - > op1 ) ;
SET_UNUSED ( opline - > op2 ) ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_extended_fcall_end ( TSRMLS_D ) /* { { { */
1999-04-08 02:10:10 +08:00
{
zend_op * opline ;
2006-05-10 07:53:23 +08:00
2008-03-18 16:36:30 +08:00
if ( ! ( CG ( compiler_options ) & ZEND_COMPILE_EXTENDED_INFO ) ) {
1999-04-08 02:10:10 +08:00
return ;
}
2006-05-10 07:53:23 +08:00
2001-07-28 18:51:54 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
1999-04-08 02:10:10 +08:00
opline - > opcode = ZEND_EXT_FCALL_END ;
SET_UNUSED ( opline - > op1 ) ;
SET_UNUSED ( opline - > op2 ) ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-07-27 22:11:53 +08:00
void zend_do_ticks ( TSRMLS_D ) /* { { { */
2000-01-25 03:00:30 +08:00
{
2011-06-12 09:43:10 +08:00
zend_op * opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
2000-01-25 03:00:30 +08:00
2011-06-12 09:43:10 +08:00
opline - > opcode = ZEND_TICKS ;
SET_UNUSED ( opline - > op1 ) ;
SET_UNUSED ( opline - > op2 ) ;
opline - > extended_value = Z_LVAL ( CG ( declarables ) . ticks ) ;
2000-01-25 03:00:30 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2000-01-25 03:00:30 +08:00
2014-02-10 14:04:30 +08:00
zend_bool zend_is_auto_global ( zend_string * name TSRMLS_DC ) /* { { { */
2003-03-02 21:33:31 +08:00
{
zend_auto_global * auto_global ;
2014-02-10 14:04:30 +08:00
if ( ( auto_global = zend_hash_find_ptr ( CG ( auto_globals ) , name ) ) ! = NULL ) {
2003-03-02 21:33:31 +08:00
if ( auto_global - > armed ) {
2014-02-10 14:04:30 +08:00
auto_global - > armed = auto_global - > auto_global_callback ( auto_global - > name TSRMLS_CC ) ;
2003-03-02 21:33:31 +08:00
}
return 1 ;
}
return 0 ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
2003-03-02 21:33:31 +08:00
2014-02-10 14:04:30 +08:00
int zend_register_auto_global ( zend_string * name , zend_bool jit , zend_auto_global_callback auto_global_callback TSRMLS_DC ) /* { { { */
2001-08-09 01:18:16 +08:00
{
2003-03-02 18:04:53 +08:00
zend_auto_global auto_global ;
2014-04-10 19:50:25 +08:00
int retval ;
2003-03-02 18:04:53 +08:00
2014-02-10 14:04:30 +08:00
auto_global . name = zend_new_interned_string ( name TSRMLS_CC ) ;
2003-03-02 18:04:53 +08:00
auto_global . auto_global_callback = auto_global_callback ;
2010-07-08 22:05:11 +08:00
auto_global . jit = jit ;
2003-03-02 18:04:53 +08:00
2014-04-10 19:50:25 +08:00
retval = zend_hash_add_mem ( CG ( auto_globals ) , name , & auto_global , sizeof ( zend_auto_global ) ) ! = NULL ? SUCCESS : FAILURE ;
STR_RELEASE ( auto_global . name ) ;
return retval ;
2001-08-09 01:18:16 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2001-08-09 01:18:16 +08:00
2010-07-08 22:05:11 +08:00
ZEND_API void zend_activate_auto_globals ( TSRMLS_D ) /* { { { */
{
2014-06-17 01:11:52 +08:00
zend_auto_global * auto_global ;
ZEND_HASH_FOREACH_PTR ( CG ( auto_globals ) , auto_global ) {
if ( auto_global - > jit ) {
auto_global - > armed = 1 ;
} else if ( auto_global - > auto_global_callback ) {
auto_global - > armed = auto_global - > auto_global_callback ( auto_global - > name TSRMLS_CC ) ;
} else {
auto_global - > armed = 0 ;
}
} ZEND_HASH_FOREACH_END ( ) ;
2010-07-08 22:05:11 +08:00
}
/* }}} */
2009-07-27 22:11:53 +08:00
int zendlex ( znode * zendlval TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
int retval ;
2001-08-06 22:36:46 +08:00
if ( CG ( increment_lineno ) ) {
CG ( zend_lineno ) + + ;
CG ( increment_lineno ) = 0 ;
}
2007-05-18 21:12:05 +08:00
again :
2014-04-03 19:26:23 +08:00
Z_TYPE_INFO ( zendlval - > u . constant ) = IS_LONG ;
2001-07-28 18:51:54 +08:00
retval = lex_scan ( & zendlval - > u . constant TSRMLS_CC ) ;
2002-11-30 19:20:25 +08:00
switch ( retval ) {
1999-04-23 07:08:42 +08:00
case T_COMMENT :
2003-04-03 00:13:12 +08:00
case T_DOC_COMMENT :
1999-04-23 07:08:42 +08:00
case T_OPEN_TAG :
1999-04-08 02:10:10 +08:00
case T_WHITESPACE :
2003-05-29 17:01:55 +08:00
goto again ;
1999-04-23 07:08:42 +08:00
case T_CLOSE_TAG :
2007-05-18 21:12:05 +08:00
if ( LANG_SCNG ( yy_text ) [ LANG_SCNG ( yy_leng ) - 1 ] ! = ' > ' ) {
2001-08-06 22:36:46 +08:00
CG ( increment_lineno ) = 1 ;
}
2008-11-25 17:56:32 +08:00
if ( CG ( has_bracketed_namespaces ) & & ! CG ( in_namespace ) ) {
2013-01-28 10:02:51 +08:00
goto again ;
2008-11-25 17:56:32 +08:00
}
1999-04-08 02:10:10 +08:00
retval = ' ; ' ; /* implicit ; */
break ;
1999-04-23 07:08:42 +08:00
case T_OPEN_TAG_WITH_ECHO :
retval = T_ECHO ;
1999-04-08 02:10:10 +08:00
break ;
}
2006-05-10 07:53:23 +08:00
1999-04-08 02:10:10 +08:00
zendlval - > op_type = IS_CONST ;
return retval ;
}
2009-07-27 22:11:53 +08:00
/* }}} */
2003-02-01 09:49:15 +08:00
2009-07-27 22:11:53 +08:00
ZEND_API void zend_initialize_class_data ( zend_class_entry * ce , zend_bool nullify_handlers TSRMLS_DC ) /* { { { */
2003-02-11 00:11:24 +08:00
{
2003-02-11 00:46:05 +08:00
zend_bool persistent_hashes = ( ce - > type = = ZEND_INTERNAL_CLASS ) ? 1 : 0 ;
2003-11-13 14:40:34 +08:00
dtor_func_t zval_ptr_dtor_func = ( ( persistent_hashes ) ? ZVAL_INTERNAL_PTR_DTOR : ZVAL_PTR_DTOR ) ;
2003-02-11 00:46:05 +08:00
2003-02-11 00:11:24 +08:00
ce - > refcount = 1 ;
2014-06-17 03:32:58 +08:00
ce - > ce_flags = ZEND_ACC_CONSTANTS_UPDATED ;
2003-04-01 04:42:01 +08:00
2010-05-24 22:11:39 +08:00
ce - > default_properties_table = NULL ;
ce - > default_static_members_table = NULL ;
2014-04-21 22:25:34 +08:00
zend_hash_init_ex ( & ce - > properties_info , 8 , NULL , ( persistent_hashes ? zend_destroy_property_info_internal : zend_destroy_property_info ) , persistent_hashes , 0 ) ;
zend_hash_init_ex ( & ce - > constants_table , 8 , NULL , zval_ptr_dtor_func , persistent_hashes , 0 ) ;
zend_hash_init_ex ( & ce - > function_table , 8 , NULL , ZEND_FUNCTION_DTOR , persistent_hashes , 0 ) ;
2003-02-11 00:11:24 +08:00
2005-12-01 19:48:17 +08:00
if ( ce - > type = = ZEND_INTERNAL_CLASS ) {
# ifdef ZTS
int n = zend_hash_num_elements ( CG ( class_table ) ) ;
2010-05-25 01:07:52 +08:00
if ( CG ( static_members_table ) & & n > = CG ( last_static_member ) ) {
2005-12-01 19:48:17 +08:00
/* Support for run-time declaration: dl() */
CG ( last_static_member ) = n + 1 ;
2014-04-10 03:40:01 +08:00
CG ( static_members_table ) = realloc ( CG ( static_members_table ) , ( n + 1 ) * sizeof ( zval * ) ) ;
2010-05-25 01:07:52 +08:00
CG ( static_members_table ) [ n ] = NULL ;
2005-12-01 19:48:17 +08:00
}
2014-04-10 03:40:01 +08:00
ce - > static_members_table = ( zval * ) ( zend_intptr_t ) n ;
2005-12-01 19:48:17 +08:00
# else
2010-05-24 22:11:39 +08:00
ce - > static_members_table = NULL ;
2005-12-01 19:48:17 +08:00
# endif
} else {
2010-05-25 01:07:52 +08:00
ce - > static_members_table = ce - > default_static_members_table ;
2010-09-15 15:38:52 +08:00
ce - > info . user . doc_comment = NULL ;
2005-12-01 19:48:17 +08:00
}
2005-09-01 18:05:32 +08:00
2010-05-24 22:11:39 +08:00
ce - > default_properties_count = 0 ;
ce - > default_static_members_count = 0 ;
2003-02-11 00:11:24 +08:00
if ( nullify_handlers ) {
ce - > constructor = NULL ;
ce - > destructor = NULL ;
ce - > clone = NULL ;
ce - > __get = NULL ;
ce - > __set = NULL ;
2005-07-08 00:07:09 +08:00
ce - > __unset = NULL ;
ce - > __isset = NULL ;
2003-02-11 00:11:24 +08:00
ce - > __call = NULL ;
2007-09-29 16:52:40 +08:00
ce - > __callstatic = NULL ;
2006-05-10 07:53:23 +08:00
ce - > __tostring = NULL ;
2003-02-11 00:11:24 +08:00
ce - > create_object = NULL ;
2003-12-28 23:18:05 +08:00
ce - > get_iterator = NULL ;
ce - > iterator_funcs . funcs = NULL ;
ce - > interface_gets_implemented = NULL ;
2007-09-29 17:34:24 +08:00
ce - > get_static_method = NULL ;
2003-12-28 23:18:05 +08:00
ce - > parent = NULL ;
ce - > num_interfaces = 0 ;
ce - > interfaces = NULL ;
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
ce - > num_traits = 0 ;
ce - > traits = NULL ;
ce - > trait_aliases = NULL ;
ce - > trait_precedences = NULL ;
2005-02-23 19:15:51 +08:00
ce - > serialize = NULL ;
ce - > unserialize = NULL ;
2005-03-08 06:23:14 +08:00
ce - > serialize_func = NULL ;
ce - > unserialize_func = NULL ;
2014-02-20 09:07:34 +08:00
ce - > __debugInfo = NULL ;
2010-09-15 15:38:52 +08:00
if ( ce - > type = = ZEND_INTERNAL_CLASS ) {
ce - > info . internal . module = NULL ;
ce - > info . internal . builtin_functions = NULL ;
}
2003-02-11 00:11:24 +08:00
}
}
2009-07-27 22:11:53 +08:00
/* }}} */
2003-02-11 00:11:24 +08:00
2009-07-27 22:11:53 +08:00
int zend_get_class_fetch_type ( const char * class_name , uint class_name_len ) /* { { { */
2003-08-03 16:21:08 +08:00
{
if ( ( class_name_len = = sizeof ( " self " ) - 1 ) & &
2013-01-28 10:02:51 +08:00
! strncasecmp ( class_name , " self " , sizeof ( " self " ) - 1 ) ) {
return ZEND_FETCH_CLASS_SELF ;
2003-08-03 16:21:08 +08:00
} else if ( ( class_name_len = = sizeof ( " parent " ) - 1 ) & &
2013-01-28 10:02:51 +08:00
! strncasecmp ( class_name , " parent " , sizeof ( " parent " ) - 1 ) ) {
2003-08-03 16:21:08 +08:00
return ZEND_FETCH_CLASS_PARENT ;
2007-09-29 15:28:34 +08:00
} else if ( ( class_name_len = = sizeof ( " static " ) - 1 ) & &
2013-01-28 10:02:51 +08:00
! strncasecmp ( class_name , " static " , sizeof ( " static " ) - 1 ) ) {
2007-09-29 15:28:34 +08:00
return ZEND_FETCH_CLASS_STATIC ;
2003-08-03 16:21:08 +08:00
} else {
return ZEND_FETCH_CLASS_DEFAULT ;
}
}
2009-07-27 22:11:53 +08:00
/* }}} */
2003-08-03 16:21:08 +08:00
2014-02-10 14:04:30 +08:00
ZEND_API zend_string * zend_get_compiled_variable_name ( const zend_op_array * op_array , zend_uint var ) /* { { { */
2005-01-22 10:29:18 +08:00
{
2014-03-27 20:00:25 +08:00
return op_array - > vars [ EX_VAR_TO_NUM ( var ) ] ;
2005-01-22 10:29:18 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2005-01-22 10:29:18 +08:00
2007-09-29 03:52:53 +08:00
void zend_do_build_namespace_name ( znode * result , znode * prefix , znode * name TSRMLS_DC ) /* { { { */
{
if ( prefix ) {
* result = * prefix ;
2007-12-08 01:11:24 +08:00
if ( Z_TYPE ( result - > u . constant ) = = IS_STRING & &
Z_STRLEN ( result - > u . constant ) = = 0 ) {
2008-11-04 23:58:55 +08:00
/* namespace\ */
2014-02-10 14:04:30 +08:00
if ( Z_TYPE ( CG ( current_namespace ) ) ! = IS_UNDEF ) {
2007-12-08 01:11:24 +08:00
znode tmp ;
zval_dtor ( & result - > u . constant ) ;
tmp . op_type = IS_CONST ;
2014-02-10 14:04:30 +08:00
ZVAL_DUP ( & tmp . u . constant , & CG ( current_namespace ) ) ;
2007-12-08 01:11:24 +08:00
zend_do_build_namespace_name ( result , NULL , & tmp TSRMLS_CC ) ;
}
}
2007-09-29 03:52:53 +08:00
} else {
result - > op_type = IS_CONST ;
2014-02-28 18:24:35 +08:00
ZVAL_EMPTY_STRING ( & result - > u . constant ) ;
2007-09-29 03:52:53 +08:00
}
2008-03-26 02:08:37 +08:00
/* prefix = result */
2008-11-04 23:58:55 +08:00
zend_do_build_full_name ( NULL , result , name , 0 TSRMLS_CC ) ;
2007-09-29 03:52:53 +08:00
}
/* }}} */
2014-04-22 22:52:59 +08:00
void zend_do_begin_namespace ( znode * name , zend_bool with_bracket TSRMLS_DC ) /* { { { */
2007-09-29 03:52:53 +08:00
{
char * lcname ;
2008-11-25 17:56:32 +08:00
/* handle mixed syntax declaration or nested namespaces */
if ( ! CG ( has_bracketed_namespaces ) ) {
2014-02-10 14:04:30 +08:00
if ( Z_TYPE ( CG ( current_namespace ) ) ! = IS_UNDEF ) {
2008-11-25 17:56:32 +08:00
/* previous namespace declarations were unbracketed */
if ( with_bracket ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot mix bracketed namespace declarations with unbracketed namespace declarations " ) ;
2008-11-25 17:56:32 +08:00
}
}
} else {
/* previous namespace declarations were bracketed */
if ( ! with_bracket ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot mix bracketed namespace declarations with unbracketed namespace declarations " ) ;
2014-02-10 14:04:30 +08:00
} else if ( Z_TYPE ( CG ( current_namespace ) ) ! = IS_UNDEF | | CG ( in_namespace ) ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Namespace declarations cannot be nested " ) ;
2008-11-25 17:56:32 +08:00
}
}
2014-02-10 14:04:30 +08:00
if ( ( ( ! with_bracket & & Z_TYPE ( CG ( current_namespace ) ) = = IS_UNDEF ) | | ( with_bracket & & ! CG ( has_bracketed_namespaces ) ) ) & & CG ( active_op_array ) - > last > 0 ) {
2007-11-01 19:58:58 +08:00
/* ignore ZEND_EXT_STMT and ZEND_TICKS */
2007-09-29 03:52:53 +08:00
int num = CG ( active_op_array ) - > last ;
while ( num > 0 & &
2007-11-01 19:58:58 +08:00
( CG ( active_op_array ) - > opcodes [ num - 1 ] . opcode = = ZEND_EXT_STMT | |
CG ( active_op_array ) - > opcodes [ num - 1 ] . opcode = = ZEND_TICKS ) ) {
2007-09-29 03:52:53 +08:00
- - num ;
}
2008-11-25 17:56:32 +08:00
if ( num > 0 ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Namespace declaration statement has to be the very first statement in the script " ) ;
2007-09-29 03:52:53 +08:00
}
}
2008-11-25 17:56:32 +08:00
CG ( in_namespace ) = 1 ;
if ( with_bracket ) {
CG ( has_bracketed_namespaces ) = 1 ;
2007-09-29 03:52:53 +08:00
}
2008-11-25 17:56:32 +08:00
if ( name ) {
lcname = zend_str_tolower_dup ( Z_STRVAL ( name - > u . constant ) , Z_STRLEN ( name - > u . constant ) ) ;
if ( ( ( Z_STRLEN ( name - > u . constant ) = = sizeof ( " self " ) - 1 ) & &
! memcmp ( lcname , " self " , sizeof ( " self " ) - 1 ) ) | |
( ( Z_STRLEN ( name - > u . constant ) = = sizeof ( " parent " ) - 1 ) & &
! memcmp ( lcname , " parent " , sizeof ( " parent " ) - 1 ) ) ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use '%s' as namespace name " , Z_STRVAL ( name - > u . constant ) ) ;
2008-11-25 17:56:32 +08:00
}
efree ( lcname ) ;
2014-02-10 14:04:30 +08:00
if ( Z_TYPE ( CG ( current_namespace ) ) ! = IS_UNDEF ) {
zval_dtor ( & CG ( current_namespace ) ) ;
2008-11-25 17:56:32 +08:00
}
2014-02-10 14:04:30 +08:00
ZVAL_COPY_VALUE ( & CG ( current_namespace ) , & name - > u . constant ) ;
2007-12-13 16:57:52 +08:00
} else {
2014-02-10 14:04:30 +08:00
if ( Z_TYPE ( CG ( current_namespace ) ) ! = IS_UNDEF ) {
zval_dtor ( & CG ( current_namespace ) ) ;
ZVAL_UNDEF ( & CG ( current_namespace ) ) ;
2008-11-25 17:56:32 +08:00
}
2007-12-13 16:57:52 +08:00
}
2008-11-25 17:56:32 +08:00
2007-12-13 16:57:52 +08:00
if ( CG ( current_import ) ) {
zend_hash_destroy ( CG ( current_import ) ) ;
efree ( CG ( current_import ) ) ;
CG ( current_import ) = NULL ;
}
2013-01-28 10:02:51 +08:00
2013-07-17 02:39:33 +08:00
if ( CG ( current_import_function ) ) {
zend_hash_destroy ( CG ( current_import_function ) ) ;
efree ( CG ( current_import_function ) ) ;
CG ( current_import_function ) = NULL ;
}
2013-07-24 02:21:48 +08:00
if ( CG ( current_import_const ) ) {
zend_hash_destroy ( CG ( current_import_const ) ) ;
efree ( CG ( current_import_const ) ) ;
CG ( current_import_const ) = NULL ;
}
2011-07-08 07:07:14 +08:00
if ( CG ( doc_comment ) ) {
2014-04-15 03:53:25 +08:00
STR_RELEASE ( CG ( doc_comment ) ) ;
2011-07-08 07:07:14 +08:00
CG ( doc_comment ) = NULL ;
}
2007-09-29 03:52:53 +08:00
}
/* }}} */
2007-12-13 18:02:03 +08:00
void zend_do_use ( znode * ns_name , znode * new_name , int is_global TSRMLS_DC ) /* { { { */
2007-09-29 03:52:53 +08:00
{
2014-02-10 14:04:30 +08:00
zend_string * lcname ;
zval * name , ns , tmp ;
2007-09-29 03:52:53 +08:00
zend_bool warn = 0 ;
2014-02-10 14:04:30 +08:00
zend_class_entry * ce ;
2007-09-29 03:52:53 +08:00
if ( ! CG ( current_import ) ) {
CG ( current_import ) = emalloc ( sizeof ( HashTable ) ) ;
2014-04-21 22:25:34 +08:00
zend_hash_init ( CG ( current_import ) , 8 , NULL , ZVAL_PTR_DTOR , 0 ) ;
2007-09-29 03:52:53 +08:00
}
2014-02-10 14:04:30 +08:00
ZVAL_ZVAL ( & ns , & ns_name - > u . constant , 0 , 0 ) ;
2007-09-29 03:52:53 +08:00
if ( new_name ) {
name = & new_name - > u . constant ;
} else {
2011-09-13 21:29:35 +08:00
const char * p ;
2007-09-29 03:52:53 +08:00
2008-11-04 23:58:55 +08:00
/* The form "use A\B" is eqivalent to "use A\B as B".
So we extract the last part of compound name to use as a new_name */
2007-09-29 03:52:53 +08:00
name = & tmp ;
2014-02-10 14:04:30 +08:00
p = zend_memrchr ( Z_STRVAL ( ns ) , ' \\ ' , Z_STRLEN ( ns ) ) ;
2007-09-29 03:52:53 +08:00
if ( p ) {
2014-02-10 14:04:30 +08:00
ZVAL_STRING ( name , p + 1 ) ;
2007-09-29 03:52:53 +08:00
} else {
2014-02-10 14:04:30 +08:00
ZVAL_ZVAL ( name , & ns , 1 , 0 ) ;
warn = ! is_global & & Z_TYPE ( CG ( current_namespace ) ) = = IS_UNDEF ;
2007-09-29 03:52:53 +08:00
}
}
2014-02-10 14:04:30 +08:00
lcname = STR_ALLOC ( Z_STRLEN_P ( name ) , 0 ) ;
zend_str_tolower_copy ( lcname - > val , Z_STRVAL_P ( name ) , Z_STRLEN_P ( name ) ) ;
2007-09-29 03:52:53 +08:00
if ( ( ( Z_STRLEN_P ( name ) = = sizeof ( " self " ) - 1 ) & &
2014-02-10 14:04:30 +08:00
! memcmp ( lcname - > val , " self " , sizeof ( " self " ) - 1 ) ) | |
2012-08-22 18:32:03 +08:00
( ( Z_STRLEN_P ( name ) = = sizeof ( " parent " ) - 1 ) & &
2014-02-10 14:04:30 +08:00
! memcmp ( lcname - > val , " parent " , sizeof ( " parent " ) - 1 ) ) ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use %s as %s because '%s' is a special class name " , Z_STRVAL ( ns ) , Z_STRVAL_P ( name ) , Z_STRVAL_P ( name ) ) ;
2007-09-29 03:52:53 +08:00
}
2014-02-10 14:04:30 +08:00
if ( Z_TYPE ( CG ( current_namespace ) ) ! = IS_UNDEF ) {
2007-10-17 18:01:22 +08:00
/* Prefix import name with current namespace name to avoid conflicts with classes */
2014-02-10 14:04:30 +08:00
zend_string * c_ns_name = STR_ALLOC ( Z_STRLEN ( CG ( current_namespace ) ) + 1 + Z_STRLEN_P ( name ) , 0 ) ;
2007-10-17 18:01:22 +08:00
2014-02-10 14:04:30 +08:00
zend_str_tolower_copy ( c_ns_name - > val , Z_STRVAL ( CG ( current_namespace ) ) , Z_STRLEN ( CG ( current_namespace ) ) ) ;
c_ns_name - > val [ Z_STRLEN ( CG ( current_namespace ) ) ] = ' \\ ' ;
2014-02-21 22:55:04 +08:00
memcpy ( c_ns_name - > val + Z_STRLEN ( CG ( current_namespace ) ) + 1 , lcname - > val , Z_STRLEN_P ( name ) + 1 ) ;
2014-02-10 14:04:30 +08:00
if ( zend_hash_exists ( CG ( class_table ) , c_ns_name ) ) {
char * tmp2 = zend_str_tolower_dup ( Z_STRVAL ( ns ) , Z_STRLEN ( ns ) ) ;
2007-11-12 23:52:22 +08:00
2014-02-10 14:04:30 +08:00
if ( Z_STRLEN ( ns ) ! = Z_STRLEN ( CG ( current_namespace ) ) + 1 + Z_STRLEN_P ( name ) | |
memcmp ( tmp2 , c_ns_name - > val , Z_STRLEN ( ns ) ) ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use %s as %s because the name is already in use " , Z_STRVAL ( ns ) , Z_STRVAL_P ( name ) ) ;
2007-11-12 23:52:22 +08:00
}
2011-01-20 01:06:50 +08:00
efree ( tmp2 ) ;
2007-10-17 18:01:22 +08:00
}
2014-02-10 14:04:30 +08:00
STR_FREE ( c_ns_name ) ;
} else if ( ( ce = zend_hash_find_ptr ( CG ( class_table ) , lcname ) ) ! = NULL & &
ce - > type = = ZEND_USER_CLASS & &
ce - > info . user . filename = = CG ( compiled_filename ) ) {
char * c_tmp = zend_str_tolower_dup ( Z_STRVAL ( ns ) , Z_STRLEN ( ns ) ) ;
2007-11-12 23:52:22 +08:00
2014-02-10 14:04:30 +08:00
if ( Z_STRLEN ( ns ) ! = Z_STRLEN_P ( name ) | |
memcmp ( c_tmp , lcname - > val , Z_STRLEN ( ns ) ) ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use %s as %s because the name is already in use " , Z_STRVAL ( ns ) , Z_STRVAL_P ( name ) ) ;
2007-11-12 23:52:22 +08:00
}
2009-09-06 05:16:05 +08:00
efree ( c_tmp ) ;
2007-09-29 03:52:53 +08:00
}
2014-02-10 14:04:30 +08:00
if ( zend_hash_add ( CG ( current_import ) , lcname , & ns ) = = NULL ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use %s as %s because the name is already in use " , Z_STRVAL ( ns ) , Z_STRVAL_P ( name ) ) ;
2007-09-29 03:52:53 +08:00
}
if ( warn ) {
2011-08-16 18:46:49 +08:00
if ( ! strcmp ( Z_STRVAL_P ( name ) , " strict " ) ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " You seem to be trying to use a different language... " ) ;
2011-08-16 18:46:49 +08:00
}
2007-11-07 17:13:50 +08:00
zend_error ( E_WARNING , " The use statement with non-compound name '%s' has no effect " , Z_STRVAL_P ( name ) ) ;
2007-09-29 03:52:53 +08:00
}
2014-02-21 22:55:04 +08:00
STR_RELEASE ( lcname ) ;
2007-09-29 03:52:53 +08:00
zval_dtor ( name ) ;
}
/* }}} */
2013-11-09 10:37:38 +08:00
void zend_do_use_non_class ( znode * ns_name , znode * new_name , int is_global , int is_function , zend_bool case_sensitive , HashTable * current_import_sub , HashTable * lookup_table TSRMLS_DC ) /* { { { */
2013-07-17 02:39:33 +08:00
{
2014-02-10 14:04:30 +08:00
zend_string * lookup_name ;
zval * name , ns , tmp ;
2013-07-17 02:39:33 +08:00
zend_bool warn = 0 ;
2014-02-10 14:04:30 +08:00
ZVAL_ZVAL ( & ns , & ns_name - > u . constant , 0 , 0 ) ;
2013-07-17 02:39:33 +08:00
if ( new_name ) {
name = & new_name - > u . constant ;
} else {
const char * p ;
/* The form "use A\B" is eqivalent to "use A\B as B".
So we extract the last part of compound name to use as a new_name */
name = & tmp ;
2014-02-10 14:04:30 +08:00
p = zend_memrchr ( Z_STRVAL ( ns ) , ' \\ ' , Z_STRLEN ( ns ) ) ;
2013-07-17 02:39:33 +08:00
if ( p ) {
2014-02-10 14:04:30 +08:00
ZVAL_STRING ( name , p + 1 ) ;
2013-07-17 02:39:33 +08:00
} else {
2014-02-10 14:04:30 +08:00
ZVAL_ZVAL ( name , & ns , 1 , 0 ) ;
warn = ! is_global & & Z_TYPE ( CG ( current_namespace ) ) = = IS_UNDEF ;
2013-07-17 02:39:33 +08:00
}
}
2013-08-25 22:21:51 +08:00
if ( case_sensitive ) {
2014-04-01 21:10:15 +08:00
lookup_name = STR_COPY ( Z_STR_P ( name ) ) ;
2013-08-25 22:21:51 +08:00
} else {
2014-02-10 14:04:30 +08:00
lookup_name = STR_ALLOC ( Z_STRLEN_P ( name ) , 0 ) ;
zend_str_tolower_copy ( lookup_name - > val , Z_STRVAL_P ( name ) , Z_STRLEN_P ( name ) ) ;
2013-08-25 22:21:51 +08:00
}
2013-07-17 02:39:33 +08:00
2014-02-10 14:04:30 +08:00
if ( Z_TYPE ( CG ( current_namespace ) ) ! = IS_UNDEF ) {
2013-08-25 21:09:19 +08:00
/* Prefix import name with current namespace name to avoid conflicts with functions/consts */
2014-02-10 14:04:30 +08:00
zend_string * c_ns_name = STR_ALLOC ( Z_STRLEN ( CG ( current_namespace ) ) + 1 + Z_STRLEN_P ( name ) , 0 ) ;
2013-08-25 05:53:43 +08:00
2014-02-10 14:04:30 +08:00
zend_str_tolower_copy ( c_ns_name - > val , Z_STRVAL ( CG ( current_namespace ) ) , Z_STRLEN ( CG ( current_namespace ) ) ) ;
c_ns_name - > val [ Z_STRLEN ( CG ( current_namespace ) ) ] = ' \\ ' ;
memcpy ( c_ns_name - > val + Z_STRLEN ( CG ( current_namespace ) ) + 1 , lookup_name , Z_STRLEN_P ( name ) + 1 ) ;
if ( zend_hash_exists ( lookup_table , c_ns_name ) ) {
char * tmp2 = zend_str_tolower_dup ( Z_STRVAL ( ns ) , Z_STRLEN ( ns ) ) ;
2013-08-25 05:53:43 +08:00
2014-02-10 14:04:30 +08:00
if ( Z_STRLEN ( ns ) ! = Z_STRLEN ( CG ( current_namespace ) ) + 1 + Z_STRLEN_P ( name ) | |
memcmp ( tmp2 , c_ns_name - > val , Z_STRLEN ( ns ) ) ) {
zend_error ( E_COMPILE_ERROR , " Cannot use %s %s as %s because the name is already in use " , is_function ? " function " : " const " , Z_STRVAL ( ns ) , Z_STRVAL_P ( name ) ) ;
2013-08-25 05:53:43 +08:00
}
efree ( tmp2 ) ;
}
2014-02-10 14:04:30 +08:00
STR_FREE ( c_ns_name ) ;
2013-11-09 10:37:38 +08:00
} else if ( is_function ) {
zend_function * function ;
2013-08-25 05:53:43 +08:00
2014-02-10 14:04:30 +08:00
if ( ( function = zend_hash_find_ptr ( lookup_table , lookup_name ) ) ! = NULL & & function - > type = = ZEND_USER_FUNCTION & & strcmp ( function - > op_array . filename - > val , CG ( compiled_filename ) - > val ) = = 0 ) {
char * c_tmp = zend_str_tolower_dup ( Z_STRVAL ( ns ) , Z_STRLEN ( ns ) ) ;
2013-08-25 05:53:43 +08:00
2014-02-10 14:04:30 +08:00
if ( Z_STRLEN ( ns ) ! = Z_STRLEN_P ( name ) | |
memcmp ( c_tmp , lookup_name - > val , Z_STRLEN ( ns ) ) ) {
zend_error ( E_COMPILE_ERROR , " Cannot use function %s as %s because the name is already in use " , Z_STRVAL ( ns ) , Z_STRVAL_P ( name ) ) ;
2013-11-09 10:37:38 +08:00
}
efree ( c_tmp ) ;
}
} else {
2014-02-10 14:04:30 +08:00
zend_string * filename ;
2013-11-09 10:37:38 +08:00
2014-02-10 14:04:30 +08:00
if ( ( filename = zend_hash_find_ptr ( lookup_table , lookup_name ) ) ! = NULL & & strcmp ( filename - > val , CG ( compiled_filename ) - > val ) = = 0 ) {
char * c_tmp = zend_str_tolower_dup ( Z_STRVAL ( ns ) , Z_STRLEN ( ns ) ) ;
2013-11-09 10:37:38 +08:00
2014-02-10 14:04:30 +08:00
if ( Z_STRLEN ( ns ) ! = Z_STRLEN_P ( name ) | |
memcmp ( c_tmp , lookup_name - > val , Z_STRLEN ( ns ) ) ) {
zend_error ( E_COMPILE_ERROR , " Cannot use const %s as %s because the name is already in use " , Z_STRVAL ( ns ) , Z_STRVAL_P ( name ) ) ;
2013-11-09 10:29:23 +08:00
}
efree ( c_tmp ) ;
2013-08-25 05:53:43 +08:00
}
}
2014-02-10 14:04:30 +08:00
if ( zend_hash_add ( current_import_sub , lookup_name , & ns ) = = NULL ) {
zend_error ( E_COMPILE_ERROR , " Cannot use %s %s as %s because the name is already in use " , is_function ? " function " : " const " , Z_STRVAL ( ns ) , Z_STRVAL_P ( name ) ) ;
2013-07-17 02:39:33 +08:00
}
if ( warn ) {
2013-11-09 10:37:38 +08:00
zend_error ( E_WARNING , " The use %s statement with non-compound name '%s' has no effect " , is_function ? " function " : " const " , Z_STRVAL_P ( name ) ) ;
2013-07-17 02:39:33 +08:00
}
2014-02-10 14:04:30 +08:00
STR_RELEASE ( lookup_name ) ;
2013-07-17 02:39:33 +08:00
zval_dtor ( name ) ;
}
/* }}} */
2013-07-24 02:21:48 +08:00
void zend_do_use_function ( znode * ns_name , znode * new_name , int is_global TSRMLS_DC ) /* { { { */
{
if ( ! CG ( current_import_function ) ) {
CG ( current_import_function ) = emalloc ( sizeof ( HashTable ) ) ;
2014-04-21 22:25:34 +08:00
zend_hash_init ( CG ( current_import_function ) , 8 , NULL , ZVAL_PTR_DTOR , 0 ) ;
2013-07-24 02:21:48 +08:00
}
2013-11-09 10:37:38 +08:00
zend_do_use_non_class ( ns_name , new_name , is_global , 1 , 0 , CG ( current_import_function ) , CG ( function_table ) TSRMLS_CC ) ;
2013-07-24 02:21:48 +08:00
}
/* }}} */
void zend_do_use_const ( znode * ns_name , znode * new_name , int is_global TSRMLS_DC ) /* { { { */
{
if ( ! CG ( current_import_const ) ) {
CG ( current_import_const ) = emalloc ( sizeof ( HashTable ) ) ;
2014-04-21 22:25:34 +08:00
zend_hash_init ( CG ( current_import_const ) , 8 , NULL , ZVAL_PTR_DTOR , 0 ) ;
2013-07-24 02:21:48 +08:00
}
2013-11-09 10:37:38 +08:00
zend_do_use_non_class ( ns_name , new_name , is_global , 0 , 1 , CG ( current_import_const ) , & CG ( const_filenames ) TSRMLS_CC ) ;
2013-07-24 02:21:48 +08:00
}
/* }}} */
2007-09-29 03:52:53 +08:00
void zend_do_declare_constant ( znode * name , znode * value TSRMLS_DC ) /* { { { */
{
zend_op * opline ;
2014-02-10 14:04:30 +08:00
zval * ns_name ;
2007-09-29 03:52:53 +08:00
2014-05-07 19:03:56 +08:00
if ( ( Z_TYPE ( value - > u . constant ) = = IS_ARRAY ) | |
( Z_TYPE ( value - > u . constant ) = = IS_CONSTANT_AST & &
Z_ASTVAL ( value - > u . constant ) - > kind = = ZEND_INIT_ARRAY ) ) {
2014-05-07 07:26:13 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Arrays are not allowed as constants " ) ;
}
2008-08-29 18:17:08 +08:00
if ( zend_get_ct_const ( & name - > u . constant , 0 TSRMLS_CC ) ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot redeclare constant '%s' " , Z_STRVAL ( name - > u . constant ) ) ;
2007-09-29 03:52:53 +08:00
}
2014-02-10 14:04:30 +08:00
if ( Z_TYPE ( CG ( current_namespace ) ) ! = IS_UNDEF ) {
2008-11-12 03:45:29 +08:00
/* Prefix constant name with name of current namespace, lowercased */
2007-09-29 03:52:53 +08:00
znode tmp ;
tmp . op_type = IS_CONST ;
2014-04-03 19:26:23 +08:00
ZVAL_NEW_STR ( & tmp . u . constant , STR_ALLOC ( Z_STRLEN ( CG ( current_namespace ) ) , 0 ) ) ;
2014-02-10 14:04:30 +08:00
zend_str_tolower_copy ( Z_STRVAL ( tmp . u . constant ) , Z_STRVAL ( CG ( current_namespace ) ) , Z_STRLEN ( CG ( current_namespace ) ) ) ;
2007-09-29 03:52:53 +08:00
zend_do_build_namespace_name ( & tmp , & tmp , name TSRMLS_CC ) ;
* name = tmp ;
}
2013-08-25 06:05:55 +08:00
/* Constant name must not conflict with import names */
if ( CG ( current_import_const ) & &
2014-02-10 14:04:30 +08:00
( ns_name = zend_hash_find ( CG ( current_import_const ) , Z_STR ( name - > u . constant ) ) ) ! = NULL ) {
2013-08-25 06:05:55 +08:00
2014-02-10 14:04:30 +08:00
char * tmp = estrndup ( Z_STRVAL_P ( ns_name ) , Z_STRLEN_P ( ns_name ) ) ;
2013-08-25 06:05:55 +08:00
2014-02-10 14:04:30 +08:00
if ( Z_STRLEN_P ( ns_name ) ! = Z_STRLEN ( name - > u . constant ) | |
2013-08-25 06:05:55 +08:00
memcmp ( tmp , Z_STRVAL ( name - > u . constant ) , Z_STRLEN ( name - > u . constant ) ) ) {
zend_error ( E_COMPILE_ERROR , " Cannot declare const %s because the name is already in use " , Z_STRVAL ( name - > u . constant ) ) ;
}
efree ( tmp ) ;
}
2007-09-29 03:52:53 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
opline - > opcode = ZEND_DECLARE_CONST ;
SET_UNUSED ( opline - > result ) ;
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > op1 , name ) ;
SET_NODE ( opline - > op2 , value ) ;
2013-08-25 05:53:43 +08:00
2014-02-10 14:04:30 +08:00
zend_hash_add_ptr ( & CG ( const_filenames ) , Z_STR ( name - > u . constant ) , CG ( compiled_filename ) ) ;
2007-09-29 03:52:53 +08:00
}
/* }}} */
2008-11-25 17:56:32 +08:00
void zend_verify_namespace ( TSRMLS_D ) /* { { { */
2007-09-29 03:52:53 +08:00
{
2008-11-25 17:56:32 +08:00
if ( CG ( has_bracketed_namespaces ) & & ! CG ( in_namespace ) ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " No code may exist outside of namespace {} " ) ;
2008-11-25 17:56:32 +08:00
}
}
/* }}} */
void zend_do_end_namespace ( TSRMLS_D ) /* { { { */
{
CG ( in_namespace ) = 0 ;
2014-02-10 14:04:30 +08:00
if ( Z_TYPE ( CG ( current_namespace ) ) ! = IS_UNDEF ) {
zval_dtor ( & CG ( current_namespace ) ) ;
ZVAL_UNDEF ( & CG ( current_namespace ) ) ;
2007-09-29 03:52:53 +08:00
}
if ( CG ( current_import ) ) {
zend_hash_destroy ( CG ( current_import ) ) ;
efree ( CG ( current_import ) ) ;
CG ( current_import ) = NULL ;
}
2013-07-17 02:39:33 +08:00
if ( CG ( current_import_function ) ) {
zend_hash_destroy ( CG ( current_import_function ) ) ;
efree ( CG ( current_import_function ) ) ;
CG ( current_import_function ) = NULL ;
}
2013-07-24 02:21:48 +08:00
if ( CG ( current_import_const ) ) {
zend_hash_destroy ( CG ( current_import_const ) ) ;
efree ( CG ( current_import_const ) ) ;
CG ( current_import_const ) = NULL ;
}
2007-09-29 03:52:53 +08:00
}
/* }}} */
2008-11-25 17:56:32 +08:00
void zend_do_end_compilation ( TSRMLS_D ) /* { { { */
{
CG ( has_bracketed_namespaces ) = 0 ;
zend_do_end_namespace ( TSRMLS_C ) ;
}
/* }}} */
2014-05-29 22:21:56 +08:00
ZEND_API void zend_make_immutable_array ( zval * zv TSRMLS_DC ) /* { { { */
{
zend_constant * c ;
if ( Z_IMMUTABLE_P ( zv ) ) {
return ;
}
Z_TYPE_FLAGS_P ( zv ) = IS_TYPE_IMMUTABLE ;
2014-06-11 06:46:50 +08:00
GC_REFCOUNT ( Z_COUNTED_P ( zv ) ) = 2 ;
2014-05-29 22:21:56 +08:00
Z_ARRVAL_P ( zv ) - > u . flags & = ~ HASH_FLAG_APPLY_PROTECTION ;
2014-05-30 14:56:50 +08:00
/* store as an anonymous constant */
2014-05-29 22:21:56 +08:00
c = emalloc ( sizeof ( zend_constant ) ) ;
ZVAL_COPY_VALUE ( & c - > value , zv ) ;
c - > flags = 0 ;
c - > name = NULL ;
c - > module_number = PHP_USER_CONSTANT ;
zend_hash_next_index_insert_ptr ( EG ( zend_constants ) , c ) ;
}
/* }}} */
void zend_make_immutable_array_r ( zval * zv TSRMLS_DC ) /* { { { */
{
zval * el ;
if ( Z_IMMUTABLE_P ( zv ) ) {
return ;
}
zend_make_immutable_array ( zv TSRMLS_CC ) ;
ZEND_HASH_FOREACH_VAL ( Z_ARRVAL_P ( zv ) , el ) {
if ( Z_TYPE_P ( el ) = = IS_ARRAY ) {
zend_make_immutable_array_r ( el TSRMLS_CC ) ;
}
} ZEND_HASH_FOREACH_END ( ) ;
}
/* }}} */
2013-11-07 02:21:07 +08:00
void zend_do_constant_expression ( znode * result , zend_ast * ast TSRMLS_DC ) /* { { { */
{
if ( ast - > kind = = ZEND_CONST ) {
2014-02-10 14:04:30 +08:00
ZVAL_COPY_VALUE ( & result - > u . constant , & ast - > u . val ) ;
2013-11-07 02:21:07 +08:00
efree ( ast ) ;
2014-06-05 20:04:11 +08:00
if ( Z_TYPE ( result - > u . constant ) = = IS_ARRAY ) {
zend_make_immutable_array_r ( & result - > u . constant TSRMLS_CC ) ;
}
2013-11-07 02:21:07 +08:00
} else if ( zend_ast_is_ct_constant ( ast ) ) {
2013-12-10 18:19:17 +08:00
zend_ast_evaluate ( & result - > u . constant , ast , NULL TSRMLS_CC ) ;
2013-11-07 02:21:07 +08:00
zend_ast_destroy ( ast ) ;
2014-05-29 22:21:56 +08:00
if ( Z_TYPE ( result - > u . constant ) = = IS_ARRAY ) {
zend_make_immutable_array_r ( & result - > u . constant TSRMLS_CC ) ;
}
2013-11-07 02:21:07 +08:00
} else {
2014-02-10 14:04:30 +08:00
ZVAL_NEW_AST ( & result - > u . constant , ast ) ;
2013-11-07 02:21:07 +08:00
}
}
/* }}} */
2008-02-12 09:17:48 +08:00
/* {{{ zend_dirname
Returns directory name component of path */
2008-02-12 08:21:15 +08:00
ZEND_API size_t zend_dirname ( char * path , size_t len )
{
register char * end = path + len - 1 ;
unsigned int len_adjust = 0 ;
# ifdef PHP_WIN32
/* Note that on Win32 CWD is per drive (heritage from CP/M).
* This means dirname ( " c:foo " ) maps to " c:. " or " c: " - which means CWD on C : drive .
*/
if ( ( 2 < = len ) & & isalpha ( ( int ) ( ( unsigned char * ) path ) [ 0 ] ) & & ( ' : ' = = path [ 1 ] ) ) {
/* Skip over the drive spec (if any) so as not to change */
path + = 2 ;
len_adjust + = 2 ;
if ( 2 = = len ) {
/* Return "c:" on Win32 for dirname("c:").
2013-01-28 10:02:51 +08:00
* It would be more consistent to return " c:. "
2008-02-12 08:21:15 +08:00
* but that would require making the string * longer * .
*/
return len ;
}
}
# elif defined(NETWARE)
/*
2013-06-11 05:20:18 +08:00
* Find the first occurrence of : from the left
2008-02-12 08:21:15 +08:00
* move the path pointer to the position just after :
* increment the len_adjust to the length of path till colon character ( inclusive )
* If there is no character beyond : simple return len
*/
char * colonpos = NULL ;
colonpos = strchr ( path , ' : ' ) ;
if ( colonpos ! = NULL ) {
len_adjust = ( ( colonpos - path ) + 1 ) ;
path + = len_adjust ;
if ( len_adjust = = len ) {
return len ;
}
2011-01-20 01:17:52 +08:00
}
2008-02-12 08:21:15 +08:00
# endif
if ( len = = 0 ) {
/* Illegal use of this function */
return 0 ;
}
/* Strip trailing slashes */
while ( end > = path & & IS_SLASH_P ( end ) ) {
end - - ;
}
if ( end < path ) {
/* The path only contained slashes */
path [ 0 ] = DEFAULT_SLASH ;
path [ 1 ] = ' \0 ' ;
return 1 + len_adjust ;
}
/* Strip filename */
while ( end > = path & & ! IS_SLASH_P ( end ) ) {
end - - ;
}
if ( end < path ) {
/* No slash found, therefore return '.' */
# ifdef NETWARE
if ( len_adjust = = 0 ) {
path [ 0 ] = ' . ' ;
path [ 1 ] = ' \0 ' ;
2008-08-03 19:48:20 +08:00
return 1 ; /* only one character */
2008-02-12 08:21:15 +08:00
} else {
path [ 0 ] = ' \0 ' ;
return len_adjust ;
}
# else
path [ 0 ] = ' . ' ;
path [ 1 ] = ' \0 ' ;
return 1 + len_adjust ;
# endif
}
/* Strip slashes which came before the file name */
while ( end > = path & & IS_SLASH_P ( end ) ) {
end - - ;
}
if ( end < path ) {
path [ 0 ] = DEFAULT_SLASH ;
path [ 1 ] = ' \0 ' ;
return 1 + len_adjust ;
}
* ( end + 1 ) = ' \0 ' ;
return ( size_t ) ( end + 1 - path ) + len_adjust ;
}
/* }}} */
2008-02-12 09:17:48 +08:00
2003-02-01 09:49:15 +08:00
/*
* Local variables :
* tab - width : 4
* c - basic - offset : 4
* indent - tabs - mode : t
* End :
*/