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) \
( op_array ) - > literals [ op ] . constant
# 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 { \
CG ( active_op_array ) - > literals [ literal ] . cache_slot = 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 { \
CG ( active_op_array ) - > literals [ literal ] . cache_slot = CG ( active_op_array ) - > last_cache_slot ; \
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 { \
2011-12-28 17:59:39 +08:00
if ( CG ( active_op_array ) - > literals [ literal ] . cache_slot ! = - 1 & & \
CG ( active_op_array ) - > literals [ literal ] . cache_slot = = \
2010-05-24 22:11:39 +08:00
CG ( active_op_array ) - > last_cache_slot - POLYMORPHIC_CACHE_SLOT_SIZE ) { \
CG ( active_op_array ) - > literals [ literal ] . cache_slot = - 1 ; \
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
2009-07-27 22:11:53 +08:00
static void zend_duplicate_property_info ( zend_property_info * property_info ) /* { { { */
2003-08-24 03:37:39 +08:00
{
2014-02-10 14:04:30 +08:00
STR_ADDREF ( property_info - > name ) ;
2005-04-25 01:32:05 +08:00
if ( property_info - > doc_comment ) {
2014-02-10 14:04:30 +08:00
STR_ADDREF ( property_info - > doc_comment ) ;
2005-04-25 01:32:05 +08:00
}
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_duplicate_property_info_zval ( zval * zv ) /* { { { */
{
2014-02-17 21:59:18 +08:00
zend_property_info * property_info = emalloc ( sizeof ( zend_property_info ) ) ;
memcpy ( property_info , Z_PTR_P ( zv ) , sizeof ( zend_property_info ) ) ;
Z_PTR_P ( zv ) = property_info ;
zend_duplicate_property_info ( property_info ) ;
2014-02-17 15:50:32 +08:00
}
/* }}} */
2009-07-27 22:11:53 +08:00
static void zend_duplicate_property_info_internal ( zend_property_info * property_info ) /* { { { */
2003-08-24 03:37:39 +08:00
{
2014-02-10 14:04:30 +08:00
STR_ADDREF ( property_info - > name ) ;
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_duplicate_property_info_internal_zval ( zval * zv ) /* { { { */
{
2014-02-17 21:59:18 +08:00
zend_property_info * property_info = pemalloc ( sizeof ( zend_property_info ) , 1 ) ;
memcpy ( property_info , Z_PTR_P ( zv ) , sizeof ( zend_property_info ) ) ;
Z_PTR_P ( zv ) = property_info ;
zend_duplicate_property_info_internal ( 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-02-10 14:04:30 +08:00
ZVAL_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
{
zend_stack_init ( & CG ( bp_stack ) ) ;
zend_stack_init ( & CG ( function_call_stack ) ) ;
zend_stack_init ( & CG ( switch_cond_stack ) ) ;
1999-09-09 22:15:17 +08:00
zend_stack_init ( & CG ( foreach_copy_stack ) ) ;
1999-04-08 02:10:10 +08:00
zend_stack_init ( & CG ( object_stack ) ) ;
2000-01-25 03:00:30 +08:00
zend_stack_init ( & CG ( declare_stack ) ) ;
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 ) ;
2001-07-16 23:48:31 +08:00
zend_stack_init ( & CG ( list_stack ) ) ;
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 ;
2013-08-25 05:53:43 +08:00
zend_hash_init ( & CG ( const_filenames ) , 0 , NULL , NULL , 0 ) ;
2001-07-28 18:51:54 +08:00
init_compiler_declarables ( TSRMLS_C ) ;
2010-09-15 15:38:52 +08:00
zend_stack_init ( & CG ( context_stack ) ) ;
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-02-17 21:59:18 +08:00
zend_hash_init ( & CG ( filenames_table ) , 5 , 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 ) ) ;
1999-05-22 10:13:01 +08:00
zend_llist_destroy ( & CG ( open_files ) ) ;
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)(zend_uintptr_t)EX_VAR_NUM_2(0, (op_array->T)++);
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 ) ;
2010-04-20 19:05:54 +08:00
return 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 ) ;
2004-10-05 03:54:35 +08:00
return i ;
}
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 ) ;
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 ) ;
//??? Z_SET_REFCOUNT(CONSTANT_EX(op_array, literal_position), 2);
//??? Z_SET_ISREF(CONSTANT_EX(op_array, literal_position));
2011-08-15 17:54:06 +08:00
op_array - > literals [ literal_position ] . cache_slot = - 1 ;
}
/* }}} */
/* 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 ( ) ) . */
2010-09-15 15:38:52 +08:00
int zend_add_literal ( zend_op_array * op_array , const 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 */
}
2010-09-15 15:38:52 +08:00
op_array - > literals = ( zend_literal * ) erealloc ( op_array - > literals , CG ( context ) . literals_size * sizeof ( zend_literal ) ) ;
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
2011-08-15 17:54:06 +08:00
/* Is used after normal compilation to append an additional literal.
Allocation is done precisely here . */
int zend_append_individual_literal ( zend_op_array * op_array , const zval * zv TSRMLS_DC ) /* { { { */
{
int i = op_array - > last_literal ;
op_array - > last_literal + + ;
op_array - > literals = ( zend_literal * ) erealloc ( op_array - > literals , ( i + 1 ) * sizeof ( zend_literal ) ) ;
zend_insert_literal ( op_array , zv , i TSRMLS_CC ) ;
2010-04-20 18:57:45 +08:00
return i ;
}
/* }}} */
2010-04-21 23:08:10 +08:00
int zend_add_func_name_literal ( zend_op_array * op_array , const 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 & &
2010-05-24 22:11:39 +08:00
& op_array - > literals [ op_array - > last_literal - 1 ] . constant = = zv & &
op_array - > literals [ op_array - > last_literal - 1 ] . cache_slot = = - 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 ) ) ;
ZVAL_STR ( & c , lc_name ) ;
zend_add_literal ( CG ( active_op_array ) , & c TSRMLS_CC ) ;
2010-04-21 22:58:33 +08:00
return ret ;
}
/* }}} */
2010-04-27 20:09:13 +08:00
int zend_add_ns_func_name_literal ( zend_op_array * op_array , const zval * zv TSRMLS_DC ) /* { { { */
{
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 & &
2010-05-24 22:11:39 +08:00
& op_array - > literals [ op_array - > last_literal - 1 ] . constant = = zv & &
op_array - > literals [ op_array - > last_literal - 1 ] . cache_slot = = - 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 ) ) ;
ZVAL_STR ( & c , lc_name ) ;
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 ) ;
ZVAL_STR ( & c , lc_name ) ;
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
2010-04-21 23:08:10 +08:00
int zend_add_class_name_literal ( zend_op_array * op_array , const 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 & &
2010-05-24 22:11:39 +08:00
& op_array - > literals [ op_array - > last_literal - 1 ] . constant = = zv & &
op_array - > literals [ op_array - > last_literal - 1 ] . cache_slot = = - 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-02-10 14:04:30 +08:00
ZVAL_STR ( & c , lc_name ) ;
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 ;
}
/* }}} */
2010-04-22 23:03:17 +08:00
int zend_add_const_name_literal ( zend_op_array * op_array , const zval * zv , int unqualified TSRMLS_DC ) /* { { { */
{
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 & &
2010-05-24 22:11:39 +08:00
& op_array - > literals [ op_array - > last_literal - 1 ] . constant = = zv & &
op_array - > literals [ op_array - > last_literal - 1 ] . cache_slot = = - 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 ) ;
ZVAL_STR ( & c , tmp_name ) ;
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 ) ;
ZVAL_STR ( & c , tmp_name ) ;
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 ) ;
ZVAL_STR ( & c , tmp_name ) ;
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 ) ;
ZVAL_STR ( & c , tmp_name ) ;
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 ) ) ;
}
/* }}} */
2009-07-27 22:11:53 +08:00
void zend_do_binary_op ( zend_uchar op , znode * result , const znode * op1 , const 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
2009-07-27 22:11:53 +08:00
void zend_do_unary_op ( zend_uchar op , znode * result , const 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
2009-07-27 22:11:53 +08:00
static void zend_do_op_data ( zend_op * data_op , const 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
2009-07-27 22:11:53 +08:00
void zend_do_binary_assign_op ( zend_uchar op , znode * result , const znode * op1 , const 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
zend_llist * fetch_list_ptr ;
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 ) ;
Z_STR ( varname - > u . constant ) = CG ( active_op_array ) - > vars [ 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 ) {
zend_stack_top ( & CG ( bp_stack ) , ( void * * ) & fetch_list_ptr ) ;
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 ) ;
}
2001-11-25 16:49:09 +08:00
zend_stack_top ( & CG ( bp_stack ) , ( void * * ) & fetch_list_ptr ) ;
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-02-10 14:04:30 +08:00
LITERAL_STR ( opline . op1 , STR_COPY ( CG ( active_op_array ) - > vars [ 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-02-10 14:04:30 +08:00
LITERAL_STR ( opline . op1 , STR_COPY ( CG ( active_op_array ) - > vars [ 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
2009-07-27 22:11:53 +08:00
void fetch_array_dim ( znode * result , const znode * parent , const znode * dim TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
1999-09-20 23:44:30 +08:00
zend_op opline ;
1999-04-08 02:10:10 +08:00
zend_llist * fetch_list_ptr ;
2010-08-25 17:14:36 +08:00
zend_stack_top ( & CG ( bp_stack ) , ( void * * ) & fetch_list_ptr ) ;
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
int numeric = 0 ;
ZEND_HANDLE_NUMERIC_EX ( Z_STRVAL ( CONSTANT ( opline . op2 . constant ) ) , Z_STRLEN ( CONSTANT ( opline . op2 . constant ) ) + 1 , index , numeric = 1 ) ;
if ( numeric ) {
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
2009-07-27 22:11:53 +08:00
void fetch_string_offset ( znode * result , const znode * parent , const 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
2009-07-27 22:11:53 +08:00
void zend_do_print ( znode * result , const 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
2009-07-27 22:11:53 +08:00
void zend_do_echo ( const 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 ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " %s function %s::%s() cannot be declared private " , method_type , CG ( active_class_entry ) - > name , 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 */
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " %s function %s::%s() cannot contain body " , method_type , CG ( active_class_entry ) - > name , 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 ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Non-abstract method %s::%s() must contain body " , CG ( active_class_entry ) - > name , 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 ) {
zend_llist * fetch_list_ptr ;
zend_stack_top ( & CG ( bp_stack ) , ( void * * ) & fetch_list_ptr ) ;
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 ,
STR_COPY ( CG ( active_op_array ) - > vars [ 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
2009-07-27 22:11:53 +08:00
void zend_do_assign_ref ( znode * result , const znode * lvar , const 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
2009-07-27 22:11:53 +08:00
void zend_do_while_cond ( const 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
2009-07-27 22:11:53 +08:00
void zend_do_for_cond ( const 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
2009-07-27 22:11:53 +08:00
void zend_do_pre_incdec ( znode * result , const 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
2009-07-27 22:11:53 +08:00
void zend_do_post_incdec ( znode * result , const 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
2009-07-27 22:11:53 +08:00
void zend_do_if_cond ( const 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 ) ;
zend_stack_push ( & CG ( bp_stack ) , ( void * ) & jmp_list , sizeof ( zend_llist ) ) ;
}
zend_stack_top ( & CG ( bp_stack ) , ( void * * ) & jmp_list_ptr ) ;
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 ) ) ;
zend_llist * jmp_list_ptr ;
zend_llist_element * le ;
zend_stack_top ( & CG ( bp_stack ) , ( void * * ) & jmp_list_ptr ) ;
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 ) ;
1999-04-08 02:10:10 +08:00
zend_stack_push ( & CG ( bp_stack ) , ( void * ) & fetch_list , sizeof ( zend_llist ) ) ;
}
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
{
zend_llist * fetch_list_ptr ;
zend_llist_element * le ;
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
zend_stack_top ( & CG ( bp_stack ) , ( void * * ) & fetch_list_ptr ) ;
le = fetch_list_ptr - > head ;
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
2009-07-27 22:11:53 +08:00
void zend_do_add_string ( znode * result , const 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
2009-07-27 22:11:53 +08:00
void zend_do_add_variable ( znode * result , const znode * op1 , const 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 ) ) ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Access type for interface method %s::%s() must be omitted " , CG ( active_class_entry ) - > name , 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
2010-09-15 15:38:52 +08:00
zend_stack_push ( & CG ( context_stack ) , ( void * ) & CG ( context ) , sizeof ( CG ( context ) ) ) ;
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 " ) ;
}
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-10 14:04:30 +08:00
} else if ( ( name - > len = = sizeof ( ZEND_CONSTRUCTOR_FUNC_NAME ) - 1 ) & & ( ! memcmp ( lcname - > val , ZEND_CONSTRUCTOR_FUNC_NAME , sizeof ( ZEND_CONSTRUCTOR_FUNC_NAME ) ) ) ) {
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 " ) ;
}
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 ) ) ;
2010-09-15 15:38:52 +08:00
zend_stack_push ( & CG ( context_stack ) , ( void * ) & CG ( context ) , sizeof ( CG ( context ) ) ) ;
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 ;
zend_stack_push ( & CG ( switch_cond_stack ) , ( void * ) & switch_entry , sizeof ( 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
2012-05-19 20:21:49 +08:00
zend_stack_push ( & CG ( foreach_copy_stack ) , ( void * ) & dummy_opline , sizeof ( zend_op ) ) ;
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
2013-09-27 01:43:32 +08:00
void zend_do_receive_param ( zend_uchar op , znode * varname , const 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 ) ;
Z_STR ( varname - > u . constant ) = CG ( active_op_array ) - > vars [ 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 = zend_new_interned_string(estrndup(Z_STRVAL(varname->u.constant), Z_STRLEN(varname->u.constant)), Z_STRLEN(varname->u.constant) + 1, 1 TSRMLS_CC);
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 ;
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
2011-06-03 09:09:32 +08:00
if ( class_type - > u . constant . type ! = IS_NULL ) {
2011-08-16 18:44:47 +08:00
if ( class_type - > u . constant . type = = IS_ARRAY ) {
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 ;
} else if ( Z_TYPE ( initialization - > u . constant ) ! = IS_ARRAY & & Z_TYPE ( initialization - > u . constant ) ! = IS_CONSTANT_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
}
2011-08-16 18:44:47 +08:00
} else if ( class_type - > u . constant . type = = IS_CALLABLE ) {
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 ) ;
2013-09-13 21:07:47 +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 ) ;
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
}
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
2008-03-12 18:40:02 +08:00
zend_stack_push ( & CG ( function_call_stack ) , ( void * ) & function , sizeof ( zend_function * ) ) ;
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 ;
1999-04-08 02:10:10 +08:00
unsigned char * ptr = NULL ;
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-02-10 14:04:30 +08:00
Z_STR ( name ) = STR_DUP ( Z_STR ( name ) , 0 ) ;
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
zend_stack_push ( & CG ( function_call_stack ) , ( void * ) & ptr , sizeof ( zend_function * ) ) ;
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
2009-07-27 22:11:53 +08:00
void zend_do_clone ( znode * result , const 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
{
unsigned char * ptr = NULL ;
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
1999-06-07 01:35:42 +08:00
zend_stack_push ( & CG ( function_call_stack ) , ( void * ) & ptr , sizeof ( zend_function * ) ) ;
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 ) {
2013-07-17 02:39:33 +08:00
len = Z_STRLEN ( element_name - > u . constant ) + 1 ;
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 ) ;
zval_copy_ctor ( & element_name - > u . constant ) ;
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 ) ;
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-10 14:04:30 +08:00
memmove ( Z_STRVAL ( class_name - > u . constant ) , Z_STRVAL ( class_name - > u . constant ) + 1 , Z_STRLEN ( class_name - > u . constant ) - 1 ) ;
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 ) ;
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
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 ) ;
zend_hash_init ( CG ( context ) . labels , 4 , NULL , NULL , 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 ) ;
Z_TYPE_P ( label ) = IS_NULL ;
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
}
/* }}} */
2008-08-13 01:20:25 +08:00
void zend_do_goto ( const 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 ) ) ) {
2010-09-15 15:38:52 +08:00
zend_compiler_context * ctx ;
2008-03-28 22:35:01 +08:00
2010-09-15 15:38:52 +08:00
zend_stack_top ( & CG ( context_stack ) , ( void * * ) & ctx ) ;
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-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-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 ;
1999-04-08 02:10:10 +08:00
unsigned char * ptr = NULL ;
2007-09-29 03:52:53 +08:00
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
1999-06-07 01:35:42 +08:00
zend_stack_push ( & CG ( function_call_stack ) , ( void * ) & ptr , sizeof ( zend_function * ) ) ;
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
2009-07-27 22:11:53 +08:00
void zend_do_end_function_call ( znode * function_name , znode * result , const znode * argument_list , 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 ;
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 */
2006-05-10 07:53:23 +08:00
if ( Z_LVAL ( argument_list - > u . constant ) ! = 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 {
2013-08-29 17:35:11 +08:00
zend_function * * function_ptr_ptr ;
zend_stack_top ( & CG ( function_call_stack ) , ( void * * ) & function_ptr_ptr ) ;
2003-05-20 01:12:56 +08:00
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
2013-08-29 17:35:11 +08:00
if ( * function_ptr_ptr ) {
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 ;
2014-02-10 14:04:30 +08:00
//??? CALCULATE_LITERAL_HASH(opline->op1.constant);
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 ) ;
2001-08-30 23:26:30 +08:00
1999-04-08 02:10:10 +08:00
zend_stack_del_top ( & CG ( function_call_stack ) ) ;
2006-05-10 07:53:23 +08:00
opline - > extended_value = Z_LVAL ( argument_list - > u . constant ) ;
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 ;
}
CG ( context ) . used_stack - = Z_LVAL ( argument_list - > 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
2009-07-27 22:11:53 +08:00
void zend_do_pass_param ( znode * param , zend_uchar op , int offset 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 ;
1999-06-07 01:35:42 +08:00
zend_function * * function_ptr_ptr , * function_ptr ;
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
1999-06-07 01:35:42 +08:00
zend_stack_top ( & CG ( function_call_stack ) , ( void * * ) & function_ptr_ptr ) ;
function_ptr = * function_ptr_ptr ;
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 & &
! ARG_SHOULD_BE_SENT_BY_REF ( function_ptr , ( zend_uint ) offset ) ) {
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(). " ,
function_ptr - > common . function_name ) ;
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 ) {
2005-08-10 20:02:52 +08:00
if ( ARG_MAY_BE_SENT_BY_REF ( function_ptr , ( zend_uint ) offset ) ) {
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 ;
}
2013-08-29 02:12:54 +08:00
} else if ( ARG_SHOULD_BE_SENT_BY_REF ( function_ptr , ( zend_uint ) offset ) ) {
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 {
2008-05-07 20:04:39 +08:00
zend_do_end_variable_parse ( param , BP_VAR_FUNC_ARG , offset 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 ) ;
opline - > op2 . opline_num = offset ;
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
2013-08-29 17:35:11 +08:00
void zend_do_unpack_params ( znode * params , int offset TSRMLS_DC ) /* { { { */
{
zend_op * opline ;
zend_function * * function_ptr_ptr ;
zend_stack_top ( & CG ( function_call_stack ) , ( void * * ) & function_ptr_ptr ) ;
if ( * function_ptr_ptr ) {
/* 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-02-10 14:04:30 +08:00
ZVAL_STR ( & func_name , STR_COPY ( ( * function_ptr_ptr ) - > 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 ;
* function_ptr_ptr = NULL ;
}
opline = get_next_op ( CG ( active_op_array ) TSRMLS_CC ) ;
opline - > opcode = ZEND_SEND_UNPACK ;
SET_NODE ( opline - > op1 , params ) ;
SET_UNUSED ( opline - > op2 ) ;
opline - > op2 . num = ( zend_uint ) offset ;
}
/* }}} */
2009-07-27 22:11:53 +08:00
static int generate_free_switch_expr ( const 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 ) ) {
2008-05-07 20:04:39 +08:00
zend_do_end_variable_parse ( expr , BP_VAR_W , 0 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
2012-07-22 03:05:46 +08:00
void zend_do_yield ( znode * result , znode * value , const 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 ) ) {
zend_do_end_variable_parse ( value , BP_VAR_W , 0 TSRMLS_CC ) ;
} 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 ) ;
zend_stack_push ( & CG ( bp_stack ) , ( void * ) & jmp_list , sizeof ( zend_llist ) ) ;
zend_stack_top ( & CG ( bp_stack ) , ( void * * ) & jmp_list_ptr ) ;
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 ) ;
Z_STR ( catch_var - > u . constant ) = CG ( active_op_array ) - > vars [ 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 */
zend_stack_top ( & CG ( bp_stack ) , ( void * * ) & jmp_list_ptr ) ;
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
2009-07-27 22:11:53 +08:00
void zend_do_throw ( const 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 ) ;
2006-10-03 19:10:33 +08:00
zend_hash_init ( op_array - > static_variables , zend_hash_num_elements ( static_variables ) , NULL , ZVAL_PTR_DTOR , 0 ) ;
2014-02-10 14:04:30 +08:00
zend_hash_copy ( op_array - > static_variables , static_variables , zval_add_ref ) ;
1999-12-24 03:23:36 +08:00
}
2010-05-24 22:11:39 +08:00
op_array - > run_time_cache = NULL ;
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 ;
}
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-02-17 21:59:18 +08:00
static void do_inherit_method ( zval * zv ) /* { { { */
2002-12-07 01:09:44 +08:00
{
2014-02-17 21:59:18 +08:00
zend_function * old_function = Z_PTR_P ( zv ) ;
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 ) ;
Z_PTR_P ( zv ) = 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
2013-09-27 00:39:17 +08:00
if ( ! strcasecmp ( fe_arg_info - > class_name , " parent " ) & & proto - > common . scope ) {
2014-02-10 14:04:30 +08:00
fe_class_name = STR_INIT (
proto - > common . scope - > name - > val ,
proto - > common . scope - > name - > len , 0 ) ;
2013-09-27 00:39:17 +08:00
} else if ( ! strcasecmp ( fe_arg_info - > class_name , " self " ) & & fe - > common . scope ) {
2014-02-10 14:04:30 +08:00
fe_class_name = STR_INIT (
fe - > common . scope - > name - > val ,
fe - > common . scope - > name - > len , 0 ) ;
2012-03-02 11:32:12 +08:00
} else {
2014-02-10 14:04:30 +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
}
2013-09-27 00:39:17 +08:00
if ( ! strcasecmp ( proto_arg_info - > class_name , " parent " ) & & proto - > common . scope & & proto - > common . scope - > parent ) {
2014-02-10 14:04:30 +08:00
proto_class_name = STR_INIT (
proto - > common . scope - > parent - > name - > val ,
proto - > common . scope - > parent - > name - > len , 0 ) ;
2013-09-27 00:39:17 +08:00
} else if ( ! strcasecmp ( proto_arg_info - > class_name , " self " ) & & proto - > common . scope ) {
2014-02-10 14:04:30 +08:00
proto_class_name = STR_INIT (
proto - > common . scope - > name - > val ,
proto - > common . scope - > name - > len , 0 ) ;
2012-03-02 11:32:12 +08:00
} else {
2014-02-10 14:04:30 +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 ) {
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 ) {
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
}
}
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 ) {
2012-03-02 11:32:12 +08:00
const char * class_name ;
zend_uint class_name_len ;
if ( ! strcasecmp ( arg_info - > class_name , " self " ) & & fptr - > common . scope ) {
2014-02-10 14:04:30 +08:00
class_name = fptr - > common . scope - > name - > val ;
class_name_len = fptr - > common . scope - > name - > len ;
2012-03-02 11:32:12 +08:00
} else if ( ! strcasecmp ( arg_info - > class_name , " parent " ) & & fptr - > common . scope - > parent ) {
2014-02-10 14:04:30 +08:00
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 ;
class_name_len = arg_info - > class_name_len ;
}
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-02-10 14:04:30 +08:00
zval zv , zv_copy ;
2011-09-23 23:08:11 +08:00
int use_copy ;
2014-02-10 14:04:30 +08:00
ZVAL_DUP ( & zv , precv - > op2 . zv ) ;
//??? INIT_PZVAL(zv);
2011-09-23 23:08:11 +08:00
zval_update_constant_ex ( & zv , ( void * ) 1 , fptr - > common . scope TSRMLS_CC ) ;
2014-02-10 14:04:30 +08:00
if ( Z_TYPE ( zv ) = = IS_BOOL ) {
if ( Z_LVAL ( zv ) ) {
2011-09-23 23:08:11 +08:00
memcpy ( offset , " true " , 4 ) ;
offset + = 4 ;
} else {
memcpy ( offset , " false " , 5 ) ;
offset + = 5 ;
}
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-02-10 14:04:30 +08:00
zend_make_printable_zval ( & zv , & zv_copy , & use_copy ) ;
2011-10-07 12:14:31 +08:00
REALLOC_BUF_IF_EXCEED ( buf , offset , length , Z_STRLEN ( zv_copy ) ) ;
memcpy ( offset , Z_STRVAL ( zv_copy ) , Z_STRLEN ( zv_copy ) ) ;
offset + = Z_STRLEN ( zv_copy ) ;
2011-09-23 23:08:11 +08:00
if ( use_copy ) {
zval_dtor ( & zv_copy ) ;
}
}
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) " ,
2004-01-28 18:25:45 +08:00
parent - > common . scope - > name ,
child - > common . function_name ,
2004-01-28 19:53:52 +08:00
child - > common . prototype ? child - > common . prototype - > common . scope - > name : child - > common . scope - > name ) ;
2004-01-28 18:25:45 +08:00
}
2003-02-24 20:05:58 +08:00
if ( parent_flags & ZEND_ACC_FINAL ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot override final method %s::%s() " , ZEND_FN_SCOPE_NAME ( parent ) , child - > common . function_name ) ;
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 ) {
2013-10-20 05:22:20 +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 , ZEND_FN_SCOPE_NAME ( child ) ) ;
2002-11-24 04:44:12 +08:00
} else {
2013-10-20 05:22:20 +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 , 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 ) ) {
2013-10-20 05:22:20 +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 , 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 ) ) {
2013-10-20 05:22:20 +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 , 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 ) ) {
2013-10-20 05:22:20 +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 , 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-02-17 15:50:32 +08:00
static zend_bool do_inherit_method_check ( HashTable * child_function_table , zval * zv , const zend_hash_key * hash_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
{
2014-02-17 15:50:32 +08:00
zend_function * parent = Z_PTR_P ( zv ) ;
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-02-10 14:04:30 +08:00
if ( ( child = zend_hash_find_ptr ( child_function_table , hash_key - > 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-02-17 15:50:32 +08:00
static zend_bool do_inherit_property_access_check ( HashTable * target_ht , zval * zv , const zend_hash_key * hash_key , zend_class_entry * ce ) /* { { { */
2003-02-04 20:12:34 +08:00
{
2014-02-17 15:50:32 +08:00
zend_property_info * parent_info = Z_PTR_P ( zv ) ;
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-02-10 14:04:30 +08:00
if ( ( child_info = zend_hash_find_ptr ( & ce - > properties_info , hash_key - > 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 {
2014-02-10 14:04:30 +08:00
child_info = zend_hash_update_mem ( & ce - > properties_info , hash_key - > key , parent_info , sizeof ( zend_property_info ) ) ;
2005-06-10 01:20:44 +08:00
if ( ce - > type & ZEND_INTERNAL_CLASS ) {
zend_duplicate_property_info_internal ( child_info ) ;
} else {
zend_duplicate_property_info ( child_info ) ;
}
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-02-10 14:04:30 +08:00
if ( ( child_info = zend_hash_find_ptr ( & ce - > properties_info , hash_key - > 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-02-10 14:04:30 +08:00
( parent_info - > flags & ZEND_ACC_STATIC ) ? " static " : " non static " , parent_ce - > name - > val , hash_key - > key - > val ,
( child_info - > flags & ZEND_ACC_STATIC ) ? " static " : " non static " , ce - > name - > val , hash_key - > 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-02-10 14:04:30 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Access level to %s::$%s must be %s (as in class %s)%s " , ce - > name - > val , hash_key - > 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
static void zval_internal_ctor ( zval * * p ) /* { { { */
2003-09-04 00:13:40 +08:00
{
2010-08-11 17:38:41 +08:00
zval * orig_ptr = * p ;
2003-09-04 00:13:40 +08:00
2010-08-11 17:38:41 +08:00
ALLOC_ZVAL ( * p ) ;
MAKE_COPY_ZVAL ( & orig_ptr , * p ) ;
2006-12-06 03:03:51 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2003-09-04 00:13:40 +08:00
2010-08-11 17:38:41 +08:00
# define zval_property_ctor(parent_ce, ce) \
2014-02-10 14:04:30 +08:00
( ( ( parent_ce ) - > type ! = ( ce ) - > type ) ? zval_internal_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
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 ;
2003-03-05 19:14:44 +08:00
if ( ( ce - > ce_flags & ZEND_ACC_INTERFACE )
& & ! ( parent_ce - > ce_flags & ZEND_ACC_INTERFACE ) ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Interface %s may not inherit from class (%s) " , ce - > name , parent_ce - > name ) ;
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 ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Class %s may not inherit from final class (%s) " , ce - > name , parent_ce - > name ) ;
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 + + ) {
2014-02-17 15:50:32 +08:00
ZVAL_COPY_VALUE ( & ce - > default_properties_table [ i ] , & parent_ce - > default_properties_table [ i ] ) ;
if ( IS_REFCOUNTED ( Z_TYPE ( ce - > default_properties_table [ i ] ) ) ) {
2010-08-11 17:38:41 +08:00
# ifdef ZTS
if ( parent_ce - > type ! = ce - > type ) {
zval * p ;
ALLOC_ZVAL ( p ) ;
MAKE_COPY_ZVAL ( & ce - > default_properties_table [ i ] , p ) ;
ce - > default_properties_table [ i ] = p ;
} else {
Z_ADDREF_P ( ce - > default_properties_table [ i ] ) ;
}
# else
2014-02-10 14:04:30 +08:00
Z_ADDREF ( ce - > default_properties_table [ i ] ) ;
2010-08-11 17:38:41 +08:00
# endif
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 ;
ce - > default_static_members_table = erealloc ( ce - > default_static_members_table , sizeof ( void * ) * i ) ;
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 + + ) {
SEPARATE_ZVAL_TO_MAKE_IS_REF ( & CE_STATIC_MEMBERS ( parent_ce ) [ i ] ) ;
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 ] ) ;
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 ;
ce - > default_static_members_table = perealloc ( ce - > default_static_members_table , sizeof ( void * ) * i , ce - > type = = ZEND_INTERNAL_CLASS ) ;
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 + + ) {
SEPARATE_ZVAL_TO_MAKE_IS_REF ( & parent_ce - > default_static_members_table [ i ] ) ;
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 ] ) ;
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
2010-05-24 22:11:39 +08:00
for ( zend_hash_internal_pointer_reset ( & ce - > properties_info ) ;
2014-02-10 14:04:30 +08:00
( property_info = zend_hash_get_current_data_ptr ( & ce - > properties_info ) ) ! = NULL ;
2011-01-20 01:17:52 +08:00
zend_hash_move_forward ( & ce - > properties_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-02-17 15:50:32 +08:00
zend_hash_merge_ex ( & ce - > properties_info , & parent_ce - > properties_info , ( ce - > type & ZEND_INTERNAL_CLASS ? zend_duplicate_property_info_internal_zval : zend_duplicate_property_info_zval ) , ( merge_checker_func_t ) do_inherit_property_access_check , ce ) ;
2002-07-16 02:09:56 +08:00
2014-02-10 14:04:30 +08:00
zend_hash_merge ( & ce - > constants_table , & parent_ce - > constants_table , zval_property_ctor ( parent_ce , ce ) , 0 ) ;
2014-02-17 21:59:18 +08:00
zend_hash_merge_ex ( & ce - > function_table , & parent_ce - > function_table , do_inherit_method , ( merge_checker_func_t ) do_inherit_method_check , ce ) ;
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-02-10 14:04:30 +08:00
static zend_bool do_inherit_constant_check ( HashTable * child_constants_table , const zval * parent_constant , const zend_hash_key * hash_key , 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-02-10 14:04:30 +08:00
if ( ( old_constant = zend_hash_find ( child_constants_table , hash_key - > key ) ) ! = NULL ) {
if ( old_constant ! = parent_constant ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot inherit previously-inherited or override constant %s from interface %s " , hash_key - > key - > 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-02-10 14:04:30 +08:00
static int do_interface_constant_check ( zval * val TSRMLS_DC , int num_args , va_list args , const zend_hash_key * key ) /* { { { */
2009-12-03 20:34:50 +08:00
{
zend_class_entry * * iface = va_arg ( args , zend_class_entry * * ) ;
2014-02-10 14:04:30 +08:00
do_inherit_constant_check ( & ( * iface ) - > constants_table , ( const zval * ) val , key , * iface ) ;
2009-12-03 20:34:50 +08:00
return ZEND_HASH_APPLY_KEEP ;
}
/* }}} */
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 ;
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 {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Class %s cannot implement previously implemented interface %s " , ce - > name , iface - > name ) ;
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 */
zend_hash_apply_with_arguments ( & ce - > constants_table TSRMLS_CC , ( apply_func_args_t ) do_interface_constant_check , 1 , & iface ) ;
} 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-02-10 14:04:30 +08:00
zend_hash_merge_ex ( & ce - > constants_table , & iface - > constants_table , ( copy_ctor_func_t ) zval_add_ref , ( merge_checker_func_t ) do_inherit_constant_check , iface ) ;
2014-02-17 21:59:18 +08:00
zend_hash_merge_ex ( & ce - > function_table , & iface - > function_table , do_inherit_method , ( merge_checker_func_t ) do_inherit_method_check , ce ) ;
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 ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " %s has colliding constructor definitions coming from traits " , ce - > name ) ;
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-02-10 14:04:30 +08:00
} else if ( ce - > name - > len + 1 = = mname - > len ) {
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 ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " %s has colliding constructor definitions coming from traits " , ce - > name ) ;
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 ) ;
zend_hash_init_ex ( * overriden , 2 , NULL , NULL , 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 " ,
2012-12-25 14:23:08 +08:00
name , ce - > name ) ;
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 " ,
2012-12-25 14:23:08 +08:00
fn - > common . scope - > name , fn - > common . function_name ,
ce - > name , name ,
existing_fn - > common . scope - > name , existing_fn - > common . function_name ) ;
# 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
2012-12-25 14:23:08 +08:00
static int zend_fixup_trait_method ( zend_function * fn , zend_class_entry * ce TSRMLS_DC ) /* { { { */
{
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
}
2012-12-25 14:23:08 +08:00
return ZEND_HASH_APPLY_KEEP ;
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
2011-07-09 03:52:21 +08:00
static int zend_traits_copy_functions ( zend_function * fn TSRMLS_DC , int num_args , va_list args , zend_hash_key * hash_key ) /* { { { */
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 ;
HashTable * * overriden ;
zend_trait_alias * alias , * * alias_ptr ;
HashTable * exclude_table ;
2014-02-10 14:04:30 +08:00
zend_string * lcname ;
2012-12-25 14:23:08 +08:00
unsigned int fnname_len ;
zend_function fn_copy ;
ce = va_arg ( args , zend_class_entry * ) ;
overriden = va_arg ( args , HashTable * * ) ;
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
exclude_table = va_arg ( args , HashTable * ) ;
2013-01-28 10:02:51 +08:00
2014-02-10 14:04:30 +08:00
fnname_len = hash_key - > key - > len ;
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-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-02-10 14:04:30 +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 , hash_key - > key - > 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 ) ;
STR_FREE ( 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-02-10 14:04:30 +08:00
lcname = hash_key - > key ;
2010-04-23 09:56:03 +08:00
2014-02-10 14:04:30 +08:00
if ( exclude_table = = NULL | | zend_hash_find ( exclude_table , lcname ) = = 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-02-10 14:04:30 +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 , lcname - > 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-02-10 14:04:30 +08:00
zend_add_trait_method ( ce , fn - > common . function_name - > val , lcname , & 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 ) {
2013-10-20 05:22:20 +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 ) ;
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 ;
}
}
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Required Trait %s wasn't added to %s " , trait - > name , ce - > 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
}
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 ) ) ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Could not find trait %s " , cur_method_ref - > class_name ) ;
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 ) ) ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Could not find trait %s " , class_name ) ;
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-10 14:04:30 +08:00
STR_FREE ( 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 ) {
2013-10-20 05:22:20 +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 , cur_method_ref - > method_name ) ;
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 ) ;
2013-10-20 05:22:20 +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 , trait - > 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
}
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 ;
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 */
zend_hash_init_ex ( & exclude_table , 2 , 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 */
2012-12-25 14:23:08 +08:00
zend_hash_apply_with_arguments ( & ce - > traits [ i ] - > function_table TSRMLS_CC , ( apply_func_args_t ) zend_traits_copy_functions , 3 , ce , & overriden , & exclude_table ) ;
2012-01-20 20:30:57 +08:00
zend_hash_destroy ( & exclude_table ) ;
2011-07-09 20:06:11 +08:00
} else {
2012-12-25 14:23:08 +08:00
zend_hash_apply_with_arguments ( & ce - > traits [ i ] - > function_table TSRMLS_CC , ( apply_func_args_t ) zend_traits_copy_functions , 3 , ce , & overriden , NULL ) ;
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
2012-12-25 14:23:08 +08:00
zend_hash_apply_with_argument ( & ce - > function_table , ( apply_func_arg_t ) zend_fixup_trait_method , ce 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
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 ;
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 + + ) {
for ( zend_hash_internal_pointer_reset ( & ce - > traits [ i ] - > properties_info ) ;
2014-02-10 14:04:30 +08:00
( property_info = zend_hash_get_current_data_ptr ( & ce - > traits [ i ] - > properties_info ) ) ! = NULL ;
2010-12-20 08:52:40 +08:00
zend_hash_move_forward ( & ce - > traits [ i ] - > properties_info ) ) {
/* 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 ) {
2010-12-20 08:52:40 +08:00
prop_name = 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 ) ;
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
}
2011-01-29 05:19:09 +08:00
Z_ADDREF_P ( prop_value ) ;
2010-12-20 08:52:40 +08:00
2014-02-10 14:04:30 +08:00
//??? doc_comment = property_info->doc_comment ? STR_DUP(property_info->doc_comment, 0) : NULL;
zend_declare_property_ex ( ce , prop_name ,
2013-01-28 10:02:51 +08:00
prop_value , flags ,
2014-02-10 14:04:30 +08:00
property_info - > doc_comment TSRMLS_CC ) ;
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 " ,
cur_alias - > alias ,
cur_alias - > trait_method - > method_name ) ;
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-17 21:59:18 +08:00
( * new_function - > op_array . refcount ) + + ;
new_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 ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Class %s cannot extend from interface %s " , ce - > name , parent_ce - > name ) ;
2010-05-07 19:09:35 +08:00
} else if ( ( parent_ce - > ce_flags & ZEND_ACC_TRAIT ) = = ZEND_ACC_TRAIT ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Class %s cannot extend from trait %s " , ce - > name , parent_ce - > name ) ;
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
2009-07-27 22:11:53 +08:00
void zend_do_boolean_or_end ( znode * result , const znode * expr1 , const znode * expr2 , 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
2009-07-27 22:11:53 +08:00
void zend_do_boolean_and_end ( znode * result , const znode * expr1 , const 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
2009-07-27 22:11:53 +08:00
void zend_do_do_while_end ( const znode * do_token , const znode * expr_open_bracket , const 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
2009-07-27 22:11:53 +08:00
void zend_do_brk_cont ( zend_uchar op , const 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 ;
1999-04-08 02:10:10 +08:00
zend_stack_push ( & CG ( switch_cond_stack ) , ( void * ) & switch_entry , sizeof ( switch_entry ) ) ;
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 ;
zend_switch_entry * switch_entry_ptr ;
2006-05-10 07:53:23 +08:00
1999-04-08 02:10:10 +08:00
zend_stack_top ( & CG ( switch_cond_stack ) , ( void * * ) & switch_entry_ptr ) ;
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
2009-07-27 22:11:53 +08:00
void zend_do_case_before_statement ( const znode * case_list , znode * case_token , const 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 ;
zend_switch_entry * switch_entry_ptr ;
znode result ;
zend_stack_top ( & CG ( switch_cond_stack ) , ( void * * ) & switch_entry_ptr ) ;
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 ) ;
1999-04-08 02:10:10 +08:00
zend_switch_entry * switch_entry_ptr ;
zend_stack_top ( & CG ( switch_cond_stack ) , ( void * * ) & switch_entry_ptr ) ;
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 ) ;
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
}
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 ) {
2013-10-20 05:22:20 +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 ) ;
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 ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Constructor %s::%s() cannot be static " , ce - > name , ce - > constructor - > common . function_name ) ;
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 ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Destructor %s::%s() cannot be static " , ce - > name , ce - > destructor - > common . function_name ) ;
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 ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Clone method %s::%s() cannot be static " , ce - > name , ce - > clone - > common . function_name ) ;
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 ) ,
CG ( active_class_entry ) - > 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
}
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 " ,
Z_STRVAL ( trait_name - > u . constant ) , CG ( active_class_entry ) - > name ) ;
}
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-02-10 14:04:30 +08:00
void zend_do_declare_property ( znode * var_name , const 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 " ,
2013-09-13 21:07:47 +08:00
CG ( active_class_entry ) - > name , 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 ) ;
zend_declare_property_ex ( CG ( active_class_entry ) , Z_STR ( var_name - > u . constant ) , & property , access_type , comment TSRMLS_CC ) ;
//??? efree(Z_STRVAL(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
2009-07-27 22:11:53 +08:00
void zend_do_declare_class_constant ( znode * var_name , const znode * value TSRMLS_DC ) /* { { { */
2002-12-07 01:09:44 +08:00
{
2014-02-10 14:04:30 +08:00
zval property ;
zend_string * cname = NULL ;
2006-05-10 07:53:23 +08:00
2004-01-09 22:02:33 +08:00
if ( Z_TYPE ( value - > u . constant ) = = IS_CONSTANT_ARRAY ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Arrays are not allowed in class constants " ) ;
2010-05-07 19:09:35 +08:00
return ;
}
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-10 14:04:30 +08:00
ZVAL_COPY_VALUE ( & property , & value - > u . constant ) ;
2013-01-28 10:02:51 +08:00
2014-02-10 14:04:30 +08:00
cname = zend_new_interned_string ( Z_STR ( var_name - > u . constant ) TSRMLS_CC ) ;
if ( zend_hash_add ( & CG ( active_class_entry ) - > constants_table , cname , & property ) = = NULL ) {
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
2009-07-27 22:11:53 +08:00
void zend_do_fetch_property ( znode * result , znode * object , const znode * property TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
1999-09-20 23:44:30 +08:00
zend_op opline ;
1999-04-08 02:10:10 +08:00
zend_llist * fetch_list_ptr ;
2006-05-10 07:53:23 +08:00
2002-01-05 23:18:30 +08:00
zend_stack_top ( & CG ( bp_stack ) , ( void * * ) & fetch_list_ptr ) ;
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 ) {
2014-02-10 14:04:30 +08:00
//??? CALCULATE_LITERAL_HASH(opline_ptr->op2.constant);
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 ) {
2014-02-10 14:04:30 +08:00
//??? CALCULATE_LITERAL_HASH(opline.op2.constant);
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
{
zend_stack_push ( & CG ( object_stack ) , object , sizeof ( znode ) ) ;
}
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 ) {
znode * tmp ;
1999-04-08 02:10:10 +08:00
2003-06-09 21:51:53 +08:00
zend_stack_top ( & CG ( object_stack ) , ( void * * ) & tmp ) ;
* 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 ;
1999-04-08 02:10:10 +08:00
unsigned char * ptr = NULL ;
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
1999-04-08 02:10:10 +08:00
zend_stack_push ( & CG ( function_call_stack ) , ( void * ) & ptr , sizeof ( unsigned char * ) ) ;
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
2009-07-27 22:11:53 +08:00
void zend_do_end_new_object ( znode * result , const znode * new_token , const znode * argument_list TSRMLS_DC ) /* { { { */
1999-04-08 02:10:10 +08:00
{
znode ctor_result ;
2001-11-05 03:30:49 +08:00
zend_do_end_function_call ( NULL , & ctor_result , argument_list , 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 ) & &
2013-11-01 23:16:58 +08:00
! IS_CONSTANT_TYPE ( Z_TYPE ( 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 ) ;
2014-02-10 14:04:30 +08:00
//??? INIT_PZVAL(&result->u.constant);
2006-03-15 17:04:36 +08:00
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 ;
2007-09-29 03:52:53 +08:00
result - > u . constant . type = IS_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 ) ;
2014-02-10 14:04:30 +08:00
//??? CALCULATE_LITERAL_HASH(opline->op2.constant);
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 ;
result - > u . constant . type = IS_CONSTANT | fetch_type ;
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
2009-07-27 22:11:53 +08:00
void zend_do_shell_exec ( znode * result , const 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 ) ) ;
//??? CALCULATE_LITERAL_HASH(opline->op1.constant);
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
2009-07-27 22:11:53 +08:00
void zend_do_init_array ( znode * result , const znode * expr , const 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 ) ;
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 ;
GET_NODE ( result , opline - > result ) ;
1999-04-08 02:10:10 +08:00
if ( expr ) {
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
int numeric = 0 ;
ZEND_HANDLE_NUMERIC_EX ( Z_STRVAL ( CONSTANT ( opline - > op2 . constant ) ) , Z_STRLEN ( CONSTANT ( opline - > op2 . constant ) ) + 1 , index , numeric = 1 ) ;
if ( numeric ) {
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
} else {
2014-02-10 14:04:30 +08:00
//??? CALCULATE_LITERAL_HASH(opline->op2.constant);
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 ) ;
}
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
2009-07-27 22:11:53 +08:00
void zend_do_add_array_element ( znode * result , const znode * expr , const 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 ) ;
1999-04-08 02:10:10 +08:00
opline - > opcode = ZEND_ADD_ARRAY_ELEMENT ;
2010-04-20 18:57:45 +08:00
SET_NODE ( opline - > result , result ) ;
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
int numeric = 0 ;
ZEND_HANDLE_NUMERIC_EX ( Z_STRVAL ( CONSTANT ( opline - > op2 . constant ) ) , Z_STRLEN ( CONSTANT ( opline - > op2 . constant ) ) + 1 , index , numeric = 1 ) ;
if ( numeric ) {
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
} else {
2014-02-10 14:04:30 +08:00
//??? CALCULATE_LITERAL_HASH(opline->op2.constant);
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
2009-07-27 22:11:53 +08:00
void zend_do_add_static_array_element ( znode * result , znode * offset , const znode * expr ) /* { { { */
1999-04-08 02:10:10 +08:00
{
2014-02-10 14:04:30 +08:00
zval element ;
1999-04-08 02:10:10 +08:00
2014-02-10 14:04:30 +08:00
ZVAL_COPY_VALUE ( & element , & expr - > u . constant ) ;
1999-04-08 02:10:10 +08:00
if ( offset ) {
2013-10-31 15:57:12 +08:00
switch ( Z_TYPE ( offset - > u . constant ) & IS_CONSTANT_TYPE_MASK ) {
2000-12-07 18:36:45 +08:00
case IS_CONSTANT :
2001-07-16 19:41:06 +08:00
/* Ugly hack to denote that this value has a constant index */
2014-02-10 14:04:30 +08:00
Z_TYPE ( element ) | = IS_CONSTANT_INDEX ;
//??? Z_STRVAL(offset->u.constant) = erealloc(Z_STRVAL(offset->u.constant), Z_STRLEN(offset->u.constant)+3);
//??? Z_STRVAL(offset->u.constant)[Z_STRLEN(offset->u.constant)+1] = Z_TYPE(offset->u.constant);
//??? Z_STRVAL(offset->u.constant)[Z_STRLEN(offset->u.constant)+2] = 0;
//??? zend_symtable_update(Z_ARRVAL(result->u.constant), Z_STRVAL(offset->u.constant), Z_STRLEN(offset->u.constant)+3, &element, sizeof(zval *), NULL);
2007-11-02 18:11:42 +08:00
zval_dtor ( & offset - > u . constant ) ;
break ;
2013-10-31 15:57:12 +08:00
case IS_CONSTANT_AST : {
/* Another ugly hack to store the data about the AST in the array */
2014-02-10 14:04:30 +08:00
//??? char* key;
//??? int len = sizeof(zend_ast *);
Z_TYPE ( element ) | = IS_CONSTANT_INDEX ;
//??? key = emalloc(len + 2);
//??? *(zend_ast **)key = Z_AST(offset->u.constant);
//??? key[len] = Z_TYPE(offset->u.constant);
//??? key[len + 1] = 0;
//??? zend_symtable_update(Z_ARRVAL(result->u.constant), key, len + 2, &element, sizeof(zval *), NULL);
//??? efree(key);
2013-11-07 02:21:07 +08:00
break ;
2013-10-31 15:57:12 +08:00
}
1999-04-08 02:10:10 +08:00
case IS_STRING :
2014-02-10 14:04:30 +08:00
zend_symtable_update ( Z_ARRVAL ( result - > u . constant ) , Z_STR ( offset - > u . constant ) , & element ) ;
1999-06-23 03:05:40 +08:00
zval_dtor ( & offset - > u . constant ) ;
1999-04-08 02:10:10 +08:00
break ;
2005-06-24 17:24:42 +08:00
case IS_NULL :
2014-02-10 14:04:30 +08:00
zend_symtable_update ( Z_ARRVAL ( result - > u . constant ) , STR_EMPTY_ALLOC ( ) , & element ) ;
2005-06-24 17:24:42 +08:00
break ;
1999-04-08 02:10:10 +08:00
case IS_LONG :
2006-05-12 05:07:39 +08:00
case IS_BOOL :
2014-02-10 14:04:30 +08:00
zend_hash_index_update ( Z_ARRVAL ( result - > u . constant ) , Z_LVAL ( offset - > u . constant ) , & element ) ;
2005-06-24 17:24:42 +08:00
break ;
case IS_DOUBLE :
2014-02-10 14:04:30 +08:00
zend_hash_index_update ( Z_ARRVAL ( result - > u . constant ) , zend_dval_to_lval ( Z_DVAL ( offset - > u . constant ) ) , & element ) ;
1999-04-08 02:10:10 +08:00
break ;
2006-02-24 02:06:47 +08:00
case IS_CONSTANT_ARRAY :
zend_error ( E_ERROR , " Illegal offset type " ) ;
break ;
1999-04-08 02:10:10 +08:00
}
} else {
2014-02-10 14:04:30 +08:00
zend_hash_next_index_insert ( Z_ARRVAL ( result - > u . constant ) , & element ) ;
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_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
{
2001-07-16 23:48:31 +08:00
zend_stack_push ( & CG ( list_stack ) , & CG ( list_llist ) , sizeof ( zend_llist ) ) ;
zend_stack_push ( & CG ( list_stack ) , & CG ( dimension_llist ) , sizeof ( zend_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 */
zend_stack_top ( & CG ( list_stack ) , ( void * * ) & p ) ;
CG ( dimension_llist ) = * p ;
zend_stack_del_top ( & CG ( list_stack ) ) ;
zend_stack_top ( & CG ( list_stack ) , ( void * * ) & p ) ;
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 ;
}
/* }}} */
2009-07-27 22:11:53 +08:00
void zend_do_fetch_static_variable ( znode * varname , const 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 ) ;
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 ) ;
zend_hash_init ( CG ( active_op_array ) - > static_variables , 2 , 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 ) ;
2014-02-10 14:04:30 +08:00
//??? if (opline->op1_type == IS_CONST) {
//??? CALCULATE_LITERAL_HASH(opline->op1.constant);
//??? }
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 ) ;
Z_TYPE ( value . u . constant ) | = is_ref ? IS_LEXICAL_REF : IS_LEXICAL_VAR ;
2014-02-10 14:04:30 +08:00
//??? Z_SET_REFCOUNT_P(&value.u.constant, 1);
//??? Z_UNSET_ISREF_P(&value.u.constant);
2013-01-28 10:02:51 +08:00
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
opline - > opcode = 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 ) ;
2014-02-10 14:04:30 +08:00
//??? if (opline->op1_type == IS_CONST) {
//??? CALCULATE_LITERAL_HASH(opline->op1.constant);
//??? }
1999-04-08 02:10:10 +08:00
SET_UNUSED ( opline - > op2 ) ;
2010-04-20 18:57:45 +08:00
opline - > extended_value = fetch_type ;
GET_NODE ( & result , opline - > result ) ;
1999-04-08 02:10:10 +08:00
if ( varname - > op_type = = IS_CONST ) {
zval_copy_ctor ( & varname - > u . constant ) ;
}
2001-07-28 18:51:54 +08:00
fetch_simple_variable ( & lval , varname , 0 TSRMLS_CC ) ; /* Relies on the fact that the default fetch is BP_VAR_W */
1999-04-08 02:10:10 +08:00
2001-07-28 18:51:54 +08:00
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 ;
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_cast ( znode * result , const 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 ;
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 ) ;
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
2009-07-27 22:11:53 +08:00
void zend_do_include_or_eval ( int type , znode * result , const 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 ) ;
STR_RELEASE ( key ) ;
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
2009-07-27 22:11:53 +08:00
void zend_do_unset ( const 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
2009-07-27 22:11:53 +08:00
void zend_do_instanceof ( znode * result , const znode * expr , const 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 ) ;
2007-01-10 23:58:08 +08:00
zend_stack_push ( & CG ( foreach_copy_stack ) , ( void * ) & dummy_opline , sizeof ( zend_op ) ) ;
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 ;
2005-02-12 06:26:45 +08:00
SET_UNUSED ( opline - > op1 ) ;
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
2004-03-01 02:25:50 +08:00
zend_stack_top ( & CG ( foreach_copy_stack ) , ( void * * ) & container_ptr ) ;
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
{
zend_stack_push ( & CG ( declare_stack ) , & CG ( declarables ) , sizeof ( zend_declarables ) ) ;
}
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 ) ) {
2009-01-09 06:36:03 +08:00
if ( ( Z_TYPE ( val - > u . constant ) & IS_CONSTANT_TYPE_MASK ) = = 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
{
zend_declarables * declarables ;
zend_stack_top ( & CG ( declare_stack ) , ( void * * ) & declarables ) ;
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
2009-07-27 22:11:53 +08:00
void zend_do_exit ( znode * result , const 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 ;
2006-05-10 07:53:23 +08:00
Z_TYPE ( result - > u . constant ) = IS_BOOL ;
Z_LVAL ( 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
2009-07-27 22:11:53 +08:00
void zend_do_end_silence ( const 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
2009-07-27 22:11:53 +08:00
void zend_do_jmp_set ( const 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
2009-07-27 22:11:53 +08:00
void zend_do_jmp_set_else ( znode * result , const znode * false_value , const znode * jmp_token , const 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
2009-07-27 22:11:53 +08:00
void zend_do_begin_qm_op ( const 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
2009-07-27 22:11:53 +08:00
void zend_do_qm_true ( const 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
2009-07-27 22:11:53 +08:00
void zend_do_qm_false ( znode * result , const znode * false_value , const 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-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-02-10 14:04:30 +08:00
return zend_hash_add_mem ( CG ( auto_globals ) , name , & auto_global , sizeof ( zend_auto_global ) ) ! = NULL ? SUCCESS : FAILURE ;
2001-08-09 01:18:16 +08:00
}
2009-07-27 22:11:53 +08:00
/* }}} */
2001-08-09 01:18:16 +08:00
2014-02-17 21:59:18 +08:00
static int zend_auto_global_init ( zval * zv TSRMLS_DC ) /* { { { */
2010-07-08 22:05:11 +08:00
{
2014-02-17 21:59:18 +08:00
zend_auto_global * auto_global = Z_PTR_P ( zv ) ;
2011-01-20 01:17:52 +08:00
if ( auto_global - > jit ) {
2010-07-08 22:05:11 +08:00
auto_global - > armed = 1 ;
2011-01-20 01:17:52 +08:00
} else if ( auto_global - > auto_global_callback ) {
2014-02-10 14:04:30 +08:00
auto_global - > armed = auto_global - > auto_global_callback ( auto_global - > name TSRMLS_CC ) ;
2010-07-08 22:05:11 +08:00
} else {
auto_global - > armed = 0 ;
}
return 0 ;
}
/* }}} */
ZEND_API void zend_activate_auto_globals ( TSRMLS_D ) /* { { { */
{
zend_hash_apply ( CG ( auto_globals ) , ( apply_func_t ) zend_auto_global_init TSRMLS_CC ) ;
}
/* }}} */
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 :
2006-05-10 07:53:23 +08:00
Z_TYPE ( 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
2014-02-10 14:04:30 +08:00
//??? INIT_PZVAL(&zendlval->u.constant);
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 ;
ce - > ce_flags = 0 ;
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-02-17 15:50:32 +08:00
zend_hash_init_ex ( & ce - > properties_info , 0 , NULL , ( persistent_hashes ? zend_destroy_property_info_internal : zend_destroy_property_info ) , persistent_hashes , 0 ) ;
2003-11-13 14:40:34 +08:00
zend_hash_init_ex ( & ce - > constants_table , 0 , NULL , zval_ptr_dtor_func , persistent_hashes , 0 ) ;
2003-02-11 00:46:05 +08:00
zend_hash_init_ex ( & ce - > function_table , 0 , 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 ;
2010-05-25 01:07:52 +08:00
CG ( static_members_table ) = realloc ( CG ( static_members_table ) , ( n + 1 ) * sizeof ( zval * * ) ) ;
CG ( static_members_table ) [ n ] = NULL ;
2005-12-01 19:48:17 +08:00
}
2010-05-24 22:11:39 +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 ;
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-02-10 14:04:30 +08:00
return op_array - > vars [ 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-10 14:04:30 +08:00
//??? Z_TYPE(result->u.constant) = IS_STRING;
//??? Z_STRVAL(result->u.constant) = NULL;
//??? Z_STRLEN(result->u.constant) = 0;
ZVAL_UNDEF ( & 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
}
/* }}} */
2008-11-25 17:56:32 +08:00
void zend_do_begin_namespace ( const 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 ) ) {
efree ( CG ( doc_comment ) ) ;
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 ) ) ;
zend_hash_init ( CG ( current_import ) , 0 , NULL , ZVAL_PTR_DTOR , 0 ) ;
}
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, 1);
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 ) ) ] = ' \\ ' ;
memcpy ( c_ns_name - > val + Z_STRLEN ( CG ( current_namespace ) ) + 1 , lcname , Z_STRLEN_P ( name ) + 1 ) ;
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
}
efree ( lcname ) ;
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, 1);
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-02-10 14:04:30 +08:00
lookup_name = STR_DUP ( Z_STR_P ( name ) , 0 ) ;
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 ) ) ;
zend_hash_init ( CG ( current_import_function ) , 0 , NULL , ZVAL_PTR_DTOR , 0 ) ;
}
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 ) ) ;
zend_hash_init ( CG ( current_import_const ) , 0 , NULL , ZVAL_PTR_DTOR , 0 ) ;
}
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
2007-11-22 18:46:26 +08:00
if ( Z_TYPE ( value - > u . constant ) = = IS_CONSTANT_ARRAY ) {
2013-10-20 05:22:20 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Arrays are not allowed as constants " ) ;
2007-11-22 18:46:26 +08:00
}
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-02-10 14:04:30 +08:00
ZVAL_STR ( & tmp . u . constant , STR_ALLOC ( Z_STRLEN ( CG ( current_namespace ) ) , 0 ) ) ;
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 ) ;
}
/* }}} */
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 ) ;
} 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 ) ;
} 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 :
*/