2014-09-19 06:01:05 +08:00
/*
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Zend Engine |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2017-01-02 23:30:12 +08:00
| Copyright ( c ) 1998 - 2017 Zend Technologies Ltd . ( http : //www.zend.com) |
2014-09-19 06:01:05 +08:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| This source file is subject to version 2.00 of the Zend license , |
| that is bundled with this package in the file LICENSE , and is |
| available through the world - wide - web at the following url : |
| http : //www.zend.com/license/2_00.txt. |
| 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 . |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Authors : Andi Gutmans < andi @ zend . com > |
| Zeev Suraski < zeev @ zend . com > |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
*/
# include "zend.h"
# include "zend_API.h"
# include "zend_compile.h"
# include "zend_execute.h"
2015-01-09 04:40:36 +08:00
# include "zend_inheritance.h"
2014-09-21 05:27:10 +08:00
# include "zend_smart_str.h"
2017-04-11 04:04:18 +08:00
# include "zend_operators.h"
2014-09-19 06:01:05 +08:00
2015-08-12 11:15:09 +08:00
static void overriden_ptr_dtor ( zval * zv ) /* { { { */
2014-09-19 06:01:05 +08:00
{
2015-08-12 11:15:09 +08:00
efree_size ( Z_PTR_P ( zv ) , sizeof ( zend_function ) ) ;
2014-09-19 06:01:05 +08:00
}
/* }}} */
2014-12-14 06:06:14 +08:00
static zend_property_info * zend_duplicate_property_info ( zend_property_info * property_info ) /* { { { */
2014-09-19 06:01:05 +08:00
{
zend_property_info * new_property_info ;
2015-01-03 17:22:58 +08:00
2014-09-19 06:01:05 +08:00
new_property_info = zend_arena_alloc ( & CG ( arena ) , sizeof ( zend_property_info ) ) ;
memcpy ( new_property_info , property_info , sizeof ( zend_property_info ) ) ;
zend_string_addref ( new_property_info - > name ) ;
if ( new_property_info - > doc_comment ) {
zend_string_addref ( new_property_info - > doc_comment ) ;
}
return new_property_info ;
}
/* }}} */
static zend_property_info * zend_duplicate_property_info_internal ( zend_property_info * property_info ) /* { { { */
{
zend_property_info * new_property_info = pemalloc ( sizeof ( zend_property_info ) , 1 ) ;
memcpy ( new_property_info , property_info , sizeof ( zend_property_info ) ) ;
zend_string_addref ( new_property_info - > name ) ;
return new_property_info ;
}
/* }}} */
2015-03-05 07:10:38 +08:00
static zend_function * zend_duplicate_function ( zend_function * func , zend_class_entry * ce ) /* { { { */
{
zend_function * new_function ;
2015-03-06 22:07:36 +08:00
if ( UNEXPECTED ( func - > type = = ZEND_INTERNAL_FUNCTION ) ) {
if ( UNEXPECTED ( ce - > type & ZEND_INTERNAL_CLASS ) ) {
2015-03-05 07:10:38 +08:00
new_function = pemalloc ( sizeof ( zend_internal_function ) , 1 ) ;
memcpy ( new_function , func , sizeof ( zend_internal_function ) ) ;
} else {
new_function = zend_arena_alloc ( & CG ( arena ) , sizeof ( zend_internal_function ) ) ;
memcpy ( new_function , func , sizeof ( zend_internal_function ) ) ;
new_function - > common . fn_flags | = ZEND_ACC_ARENA_ALLOCATED ;
}
2015-03-06 22:07:36 +08:00
if ( EXPECTED ( new_function - > common . function_name ) ) {
2015-03-05 07:10:38 +08:00
zend_string_addref ( new_function - > common . function_name ) ;
}
} else {
if ( func - > op_array . refcount ) {
( * func - > op_array . refcount ) + + ;
}
if ( EXPECTED ( ! func - > op_array . static_variables ) ) {
/* reuse the same op_array structure */
return func ;
}
if ( ! ( GC_FLAGS ( func - > op_array . static_variables ) & IS_ARRAY_IMMUTABLE ) ) {
2017-10-27 06:28:58 +08:00
GC_ADDREF ( func - > op_array . static_variables ) ;
2015-03-05 07:10:38 +08:00
}
new_function = zend_arena_alloc ( & CG ( arena ) , sizeof ( zend_op_array ) ) ;
memcpy ( new_function , func , sizeof ( zend_op_array ) ) ;
}
return new_function ;
}
/* }}} */
2014-12-14 06:06:14 +08:00
static void do_inherit_parent_constructor ( zend_class_entry * ce ) /* { { { */
2014-09-19 06:01:05 +08:00
{
2015-03-05 07:10:38 +08:00
ZEND_ASSERT ( ce - > parent ! = NULL ) ;
2014-09-19 06:01:05 +08:00
/* You cannot change create_object */
ce - > create_object = ce - > parent - > create_object ;
/* Inherit special functions if needed */
2015-03-05 07:10:38 +08:00
if ( EXPECTED ( ! ce - > get_iterator ) ) {
2014-09-19 06:01:05 +08:00
ce - > get_iterator = ce - > parent - > get_iterator ;
}
2015-03-05 07:10:38 +08:00
if ( EXPECTED ( ! ce - > iterator_funcs . funcs ) ) {
2014-09-19 06:01:05 +08:00
ce - > iterator_funcs . funcs = ce - > parent - > iterator_funcs . funcs ;
}
2015-03-05 07:10:38 +08:00
if ( EXPECTED ( ! ce - > __get ) ) {
ce - > __get = ce - > parent - > __get ;
2014-09-19 06:01:05 +08:00
}
2015-03-05 07:10:38 +08:00
if ( EXPECTED ( ! ce - > __set ) ) {
2014-09-19 06:01:05 +08:00
ce - > __set = ce - > parent - > __set ;
}
2015-03-05 07:10:38 +08:00
if ( EXPECTED ( ! ce - > __unset ) ) {
2014-09-19 06:01:05 +08:00
ce - > __unset = ce - > parent - > __unset ;
}
2015-03-05 07:10:38 +08:00
if ( EXPECTED ( ! ce - > __isset ) ) {
2014-09-19 06:01:05 +08:00
ce - > __isset = ce - > parent - > __isset ;
}
2015-03-05 07:10:38 +08:00
if ( EXPECTED ( ! ce - > __call ) ) {
2014-09-19 06:01:05 +08:00
ce - > __call = ce - > parent - > __call ;
}
2015-03-05 07:10:38 +08:00
if ( EXPECTED ( ! ce - > __callstatic ) ) {
2014-09-19 06:01:05 +08:00
ce - > __callstatic = ce - > parent - > __callstatic ;
}
2015-03-05 07:10:38 +08:00
if ( EXPECTED ( ! ce - > __tostring ) ) {
2014-09-19 06:01:05 +08:00
ce - > __tostring = ce - > parent - > __tostring ;
}
2015-03-05 07:10:38 +08:00
if ( EXPECTED ( ! ce - > clone ) ) {
2014-09-19 06:01:05 +08:00
ce - > clone = ce - > parent - > clone ;
}
2015-03-05 07:10:38 +08:00
if ( EXPECTED ( ! ce - > serialize ) ) {
2014-09-19 06:01:05 +08:00
ce - > serialize = ce - > parent - > serialize ;
}
2015-03-05 07:10:38 +08:00
if ( EXPECTED ( ! ce - > unserialize ) ) {
2014-09-19 06:01:05 +08:00
ce - > unserialize = ce - > parent - > unserialize ;
}
if ( ! ce - > destructor ) {
2015-03-05 07:10:38 +08:00
ce - > destructor = ce - > parent - > destructor ;
2014-09-19 06:01:05 +08:00
}
2015-03-05 07:10:38 +08:00
if ( EXPECTED ( ! ce - > __debugInfo ) ) {
2014-09-19 06:01:05 +08:00
ce - > __debugInfo = ce - > parent - > __debugInfo ;
}
2015-03-05 07:10:38 +08:00
2014-09-19 06:01:05 +08:00
if ( ce - > constructor ) {
2015-03-05 07:10:38 +08:00
if ( ce - > parent - > constructor & & UNEXPECTED ( ce - > parent - > constructor - > common . fn_flags & ZEND_ACC_FINAL ) ) {
zend_error_noreturn ( E_ERROR , " Cannot override final %s::%s() with %s::%s() " ,
2015-06-30 18:59:27 +08:00
ZSTR_VAL ( ce - > parent - > name ) , ZSTR_VAL ( ce - > parent - > constructor - > common . function_name ) ,
ZSTR_VAL ( ce - > name ) , ZSTR_VAL ( ce - > constructor - > common . function_name ) ) ;
2014-09-19 06:01:05 +08:00
}
return ;
}
ce - > constructor = ce - > parent - > constructor ;
}
/* }}} */
char * zend_visibility_string ( uint32_t fn_flags ) /* { { { */
{
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 " " ;
}
/* }}} */
2016-06-29 22:36:33 +08:00
static zend_always_inline zend_bool zend_iterable_compatibility_check ( zend_arg_info * arg_info ) /* { { { */
2016-06-04 22:44:49 +08:00
{
2017-01-13 16:37:46 +08:00
if ( ZEND_TYPE_CODE ( arg_info - > type ) = = IS_ARRAY ) {
2016-06-05 22:49:29 +08:00
return 1 ;
2016-06-04 22:44:49 +08:00
}
2017-01-01 22:53:24 +08:00
2017-01-13 16:37:46 +08:00
if ( ZEND_TYPE_IS_CLASS ( arg_info - > type ) & & zend_string_equals_literal_ci ( ZEND_TYPE_NAME ( arg_info - > type ) , " Traversable " ) ) {
2016-06-04 22:44:49 +08:00
return 1 ;
}
2017-01-01 22:53:24 +08:00
2016-06-04 22:44:49 +08:00
return 0 ;
}
/* }}} */
2016-03-29 18:34:18 +08:00
static int zend_do_perform_type_hint_check ( const zend_function * fe , zend_arg_info * fe_arg_info , const zend_function * proto , zend_arg_info * proto_arg_info ) /* { { { */
2015-01-09 04:40:36 +08:00
{
2017-01-01 22:53:24 +08:00
ZEND_ASSERT ( ZEND_TYPE_IS_SET ( fe_arg_info - > type ) & & ZEND_TYPE_IS_SET ( proto_arg_info - > type ) ) ;
2015-01-09 04:40:36 +08:00
2017-01-01 22:53:24 +08:00
if ( ZEND_TYPE_IS_CLASS ( fe_arg_info - > type ) & & ZEND_TYPE_IS_CLASS ( proto_arg_info - > type ) ) {
2015-01-09 04:40:36 +08:00
zend_string * fe_class_name , * proto_class_name ;
const char * class_name ;
2017-05-11 03:25:32 +08:00
size_t class_name_len ;
2015-01-09 04:40:36 +08:00
2017-01-13 16:37:46 +08:00
fe_class_name = ZEND_TYPE_NAME ( fe_arg_info - > type ) ;
class_name = ZSTR_VAL ( fe_class_name ) ;
2017-05-11 03:25:32 +08:00
class_name_len = ZSTR_LEN ( fe_class_name ) ;
if ( class_name_len = = sizeof ( " parent " ) - 1 & & ! strcasecmp ( class_name , " parent " ) & & proto - > common . scope ) {
2015-01-09 04:40:36 +08:00
fe_class_name = zend_string_copy ( proto - > common . scope - > name ) ;
2017-05-11 03:25:32 +08:00
} else if ( class_name_len = = sizeof ( " self " ) - 1 & & ! strcasecmp ( class_name , " self " ) & & fe - > common . scope ) {
2015-01-09 04:40:36 +08:00
fe_class_name = zend_string_copy ( fe - > common . scope - > name ) ;
} else {
2017-01-13 16:37:46 +08:00
zend_string_addref ( fe_class_name ) ;
2015-01-09 04:40:36 +08:00
}
2017-01-13 16:37:46 +08:00
proto_class_name = ZEND_TYPE_NAME ( proto_arg_info - > type ) ;
class_name = ZSTR_VAL ( proto_class_name ) ;
2017-05-11 03:25:32 +08:00
class_name_len = ZSTR_LEN ( proto_class_name ) ;
if ( class_name_len = = sizeof ( " parent " ) - 1 & & ! strcasecmp ( class_name , " parent " ) & & proto - > common . scope & & proto - > common . scope - > parent ) {
2015-01-09 04:40:36 +08:00
proto_class_name = zend_string_copy ( proto - > common . scope - > parent - > name ) ;
2017-05-11 03:25:32 +08:00
} else if ( class_name_len = = sizeof ( " self " ) - 1 & & ! strcasecmp ( class_name , " self " ) & & proto - > common . scope ) {
2015-01-09 04:40:36 +08:00
proto_class_name = zend_string_copy ( proto - > common . scope - > name ) ;
} else {
2017-01-13 16:37:46 +08:00
zend_string_addref ( proto_class_name ) ;
2015-01-09 04:40:36 +08:00
}
2017-05-11 03:25:32 +08:00
if ( fe_class_name ! = proto_class_name & & strcasecmp ( ZSTR_VAL ( fe_class_name ) , ZSTR_VAL ( proto_class_name ) ) ! = 0 ) {
2015-01-09 04:40:36 +08:00
if ( fe - > common . type ! = ZEND_USER_FUNCTION ) {
zend_string_release ( proto_class_name ) ;
zend_string_release ( fe_class_name ) ;
return 0 ;
2015-08-29 00:58:49 +08:00
} else {
2015-01-09 04:40:36 +08:00
zend_class_entry * fe_ce , * proto_ce ;
fe_ce = zend_lookup_class ( fe_class_name ) ;
proto_ce = zend_lookup_class ( proto_class_name ) ;
/* Check for class alias */
if ( ! fe_ce | | ! proto_ce | |
fe_ce - > type = = ZEND_INTERNAL_CLASS | |
proto_ce - > type = = ZEND_INTERNAL_CLASS | |
fe_ce ! = proto_ce ) {
zend_string_release ( proto_class_name ) ;
zend_string_release ( fe_class_name ) ;
return 0 ;
}
}
}
zend_string_release ( proto_class_name ) ;
zend_string_release ( fe_class_name ) ;
2017-01-13 16:37:46 +08:00
} else if ( ZEND_TYPE_CODE ( fe_arg_info - > type ) ! = ZEND_TYPE_CODE ( proto_arg_info - > type ) ) {
2017-01-01 22:53:24 +08:00
/* Incompatible built-in types */
2016-03-28 18:54:25 +08:00
return 0 ;
}
2015-01-09 04:40:36 +08:00
return 1 ;
}
/* }}} */
2017-01-01 22:53:24 +08:00
static int zend_do_perform_arg_type_hint_check ( const zend_function * fe , zend_arg_info * fe_arg_info , const zend_function * proto , zend_arg_info * proto_arg_info ) /* { { { */
{
if ( ! ZEND_TYPE_IS_SET ( fe_arg_info - > type ) ) {
/* Child with no type is always compatible */
return 1 ;
}
if ( ! ZEND_TYPE_IS_SET ( proto_arg_info - > type ) ) {
/* Child defines a type, but parent doesn't, violates LSP */
return 0 ;
}
return zend_do_perform_type_hint_check ( fe , fe_arg_info , proto , proto_arg_info ) ;
}
/* }}} */
2014-12-14 06:06:14 +08:00
static zend_bool zend_do_perform_implementation_check ( const zend_function * fe , const zend_function * proto ) /* { { { */
2014-09-19 06:01:05 +08:00
{
uint32_t i , num_args ;
/* 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 .
*/
if ( ! proto | | ( ! proto - > common . arg_info & & proto - > common . type ! = ZEND_USER_FUNCTION ) ) {
return 1 ;
}
/* 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 ) ) {
return 1 ;
}
2016-07-05 20:31:32 +08:00
/* If the prototype method is private do not enforce a signature */
if ( proto - > common . fn_flags & ZEND_ACC_PRIVATE ) {
2014-09-19 06:01:05 +08:00
return 1 ;
}
/* check number of arguments */
if ( proto - > common . required_num_args < fe - > common . required_num_args
| | proto - > common . num_args > fe - > common . num_args ) {
return 0 ;
}
/* 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 ) ) {
return 0 ;
}
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 ;
2014-12-22 21:44:39 +08:00
if ( proto - > common . fn_flags & ZEND_ACC_VARIADIC ) {
num_args + + ;
if ( fe - > common . num_args > = proto - > common . num_args ) {
num_args = fe - > common . num_args ;
if ( fe - > common . fn_flags & ZEND_ACC_VARIADIC ) {
num_args + + ;
}
}
2014-09-19 06:01:05 +08:00
}
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 {
2014-12-22 21:44:39 +08:00
proto_arg_info = & proto - > common . arg_info [ proto - > common . num_args ] ;
2014-09-19 06:01:05 +08:00
}
2017-01-01 22:53:24 +08:00
if ( ! zend_do_perform_arg_type_hint_check ( fe , fe_arg_info , proto , proto_arg_info ) ) {
2017-01-13 16:37:46 +08:00
switch ( ZEND_TYPE_CODE ( fe_arg_info - > type ) ) {
2016-06-29 22:36:33 +08:00
case IS_ITERABLE :
if ( ! zend_iterable_compatibility_check ( proto_arg_info ) ) {
return 0 ;
}
break ;
2017-01-01 22:53:24 +08:00
2016-06-29 22:36:33 +08:00
default :
return 0 ;
2016-06-05 15:01:01 +08:00
}
2014-09-19 06:01:05 +08:00
}
2016-04-29 16:15:26 +08:00
// This introduces BC break described at https://bugs.php.net/bug.php?id=72119
2017-01-13 16:37:46 +08:00
if ( ZEND_TYPE_IS_SET ( proto_arg_info - > type ) & & ZEND_TYPE_ALLOW_NULL ( proto_arg_info - > type ) & & ! ZEND_TYPE_ALLOW_NULL ( fe_arg_info - > type ) ) {
2016-04-06 22:17:10 +08:00
/* incompatible nullability */
return 0 ;
}
2015-01-09 04:40:36 +08:00
/* by-ref constraints on arguments are invariant */
if ( fe_arg_info - > pass_by_reference ! = proto_arg_info - > pass_by_reference ) {
return 0 ;
}
}
2014-09-19 06:01:05 +08:00
2015-03-23 01:50:36 +08:00
/* Check return type compatibility, but only if the prototype already specifies
* a return type . Adding a new return type is always valid . */
if ( proto - > common . fn_flags & ZEND_ACC_HAS_RETURN_TYPE ) {
/* Removing a return type is not valid. */
if ( ! ( fe - > common . fn_flags & ZEND_ACC_HAS_RETURN_TYPE ) ) {
2015-01-09 04:40:36 +08:00
return 0 ;
}
2017-01-01 22:53:24 +08:00
2016-06-29 22:36:33 +08:00
if ( ! zend_do_perform_type_hint_check ( fe , fe - > common . arg_info - 1 , proto , proto - > common . arg_info - 1 ) ) {
2017-01-13 16:37:46 +08:00
switch ( ZEND_TYPE_CODE ( proto - > common . arg_info [ - 1 ] . type ) ) {
2016-06-29 22:36:33 +08:00
case IS_ITERABLE :
if ( ! zend_iterable_compatibility_check ( fe - > common . arg_info - 1 ) ) {
return 0 ;
}
break ;
2017-01-01 22:53:24 +08:00
2016-06-29 22:36:33 +08:00
default :
return 0 ;
2016-06-05 15:01:01 +08:00
}
2015-01-09 04:40:36 +08:00
}
2016-04-06 23:24:34 +08:00
2017-01-13 16:37:46 +08:00
if ( ZEND_TYPE_ALLOW_NULL ( fe - > common . arg_info [ - 1 ] . type ) & & ! ZEND_TYPE_ALLOW_NULL ( proto - > common . arg_info [ - 1 ] . type ) ) {
2016-04-06 23:24:34 +08:00
return 0 ;
}
2015-01-09 04:40:36 +08:00
}
return 1 ;
}
/* }}} */
2014-09-19 06:01:05 +08:00
2015-08-19 19:40:56 +08:00
static ZEND_COLD void zend_append_type_hint ( smart_str * str , const zend_function * fptr , zend_arg_info * arg_info , int return_hint ) /* { { { */
2015-01-09 04:40:36 +08:00
{
2016-04-29 05:26:57 +08:00
2017-01-13 16:37:46 +08:00
if ( ZEND_TYPE_IS_SET ( arg_info - > type ) & & ZEND_TYPE_ALLOW_NULL ( arg_info - > type ) ) {
2016-04-29 05:26:57 +08:00
smart_str_appendc ( str , ' ? ' ) ;
}
2017-01-13 16:37:46 +08:00
if ( ZEND_TYPE_IS_CLASS ( arg_info - > type ) ) {
2015-01-09 04:40:36 +08:00
const char * class_name ;
size_t class_name_len ;
2014-09-19 06:01:05 +08:00
2017-01-13 16:37:46 +08:00
class_name = ZSTR_VAL ( ZEND_TYPE_NAME ( arg_info - > type ) ) ;
class_name_len = ZSTR_LEN ( ZEND_TYPE_NAME ( arg_info - > type ) ) ;
2015-01-09 04:40:36 +08:00
if ( ! strcasecmp ( class_name , " self " ) & & fptr - > common . scope ) {
2015-06-30 18:59:27 +08:00
class_name = ZSTR_VAL ( fptr - > common . scope - > name ) ;
class_name_len = ZSTR_LEN ( fptr - > common . scope - > name ) ;
2015-01-30 10:30:17 +08:00
} else if ( ! strcasecmp ( class_name , " parent " ) & & fptr - > common . scope & & fptr - > common . scope - > parent ) {
2015-06-30 18:59:27 +08:00
class_name = ZSTR_VAL ( fptr - > common . scope - > parent - > name ) ;
class_name_len = ZSTR_LEN ( fptr - > common . scope - > parent - > name ) ;
2014-09-19 06:01:05 +08:00
}
2015-01-09 04:40:36 +08:00
smart_str_appendl ( str , class_name , class_name_len ) ;
if ( ! return_hint ) {
smart_str_appendc ( str , ' ' ) ;
}
2017-01-13 16:37:46 +08:00
} else if ( ZEND_TYPE_IS_CODE ( arg_info - > type ) ) {
if ( ZEND_TYPE_CODE ( arg_info - > type ) = = IS_LONG ) {
2015-06-29 06:28:52 +08:00
smart_str_appendl ( str , " int " , 3 ) ;
2017-01-13 16:37:46 +08:00
} else if ( ZEND_TYPE_CODE ( arg_info - > type ) = = _IS_BOOL ) {
2015-07-03 02:34:49 +08:00
smart_str_appendl ( str , " bool " , 4 ) ;
2015-06-29 06:28:52 +08:00
} else {
2017-01-13 16:37:46 +08:00
const char * type_name = zend_get_type_by_const ( ZEND_TYPE_CODE ( arg_info - > type ) ) ;
2015-06-29 06:28:52 +08:00
smart_str_appends ( str , type_name ) ;
}
2015-01-09 04:40:36 +08:00
if ( ! return_hint ) {
smart_str_appendc ( str , ' ' ) ;
2014-09-19 06:01:05 +08:00
}
}
}
/* }}} */
2015-08-19 19:40:56 +08:00
static ZEND_COLD zend_string * zend_get_function_declaration ( const zend_function * fptr ) /* { { { */
2014-09-19 06:01:05 +08:00
{
2014-09-21 05:27:10 +08:00
smart_str str = { 0 } ;
2014-09-19 06:01:05 +08:00
if ( fptr - > op_array . fn_flags & ZEND_ACC_RETURN_REFERENCE ) {
2014-09-21 05:27:10 +08:00
smart_str_appends ( & str , " & " ) ;
2014-09-19 06:01:05 +08:00
}
if ( fptr - > common . scope ) {
2015-06-29 06:28:52 +08:00
/* cut off on NULL byte ... class@anonymous */
2015-06-30 18:59:27 +08:00
smart_str_appendl ( & str , ZSTR_VAL ( fptr - > common . scope - > name ) , strlen ( ZSTR_VAL ( fptr - > common . scope - > name ) ) ) ;
2014-09-21 05:27:10 +08:00
smart_str_appends ( & str , " :: " ) ;
2014-09-19 06:01:05 +08:00
}
2014-09-22 02:47:07 +08:00
smart_str_append ( & str , fptr - > common . function_name ) ;
2014-09-21 05:27:10 +08:00
smart_str_appendc ( & str , ' ( ' ) ;
2014-09-19 06:01:05 +08:00
if ( fptr - > common . arg_info ) {
2014-12-22 21:44:39 +08:00
uint32_t i , num_args , required ;
2014-09-19 06:01:05 +08:00
zend_arg_info * arg_info = fptr - > common . arg_info ;
required = fptr - > common . required_num_args ;
2014-12-22 21:44:39 +08:00
num_args = fptr - > common . num_args ;
if ( fptr - > common . fn_flags & ZEND_ACC_VARIADIC ) {
num_args + + ;
}
for ( i = 0 ; i < num_args ; ) {
2015-01-09 04:40:36 +08:00
zend_append_type_hint ( & str , fptr , arg_info , 0 ) ;
2014-09-19 06:01:05 +08:00
if ( arg_info - > pass_by_reference ) {
2014-09-21 05:27:10 +08:00
smart_str_appendc ( & str , ' & ' ) ;
2014-09-19 06:01:05 +08:00
}
if ( arg_info - > is_variadic ) {
2014-09-21 05:27:10 +08:00
smart_str_appends ( & str , " ... " ) ;
2014-09-19 06:01:05 +08:00
}
2014-09-21 05:27:10 +08:00
smart_str_appendc ( & str , ' $ ' ) ;
2014-09-19 06:01:05 +08:00
if ( arg_info - > name ) {
2014-12-03 21:56:09 +08:00
if ( fptr - > type = = ZEND_INTERNAL_FUNCTION ) {
smart_str_appends ( & str , ( ( zend_internal_arg_info * ) arg_info ) - > name ) ;
} else {
2015-06-30 18:59:27 +08:00
smart_str_appendl ( & str , ZSTR_VAL ( arg_info - > name ) , ZSTR_LEN ( arg_info - > name ) ) ;
2014-12-03 21:56:09 +08:00
}
2014-09-19 06:01:05 +08:00
} else {
2014-09-21 05:27:10 +08:00
smart_str_appends ( & str , " param " ) ;
smart_str_append_unsigned ( & str , i ) ;
2014-09-19 06:01:05 +08:00
}
2014-09-21 05:27:10 +08:00
2014-09-19 06:01:05 +08:00
if ( i > = required & & ! arg_info - > is_variadic ) {
2014-09-21 05:27:10 +08:00
smart_str_appends ( & str , " = " ) ;
2014-09-19 06:01:05 +08:00
if ( fptr - > type = = ZEND_USER_FUNCTION ) {
zend_op * precv = NULL ;
{
uint32_t idx = i ;
2014-09-21 05:27:10 +08:00
zend_op * op = fptr - > op_array . opcodes ;
zend_op * end = op + fptr - > op_array . last ;
2014-09-19 06:01:05 +08:00
+ + idx ;
while ( op < end ) {
if ( ( op - > opcode = = ZEND_RECV | | op - > opcode = = ZEND_RECV_INIT )
& & op - > op1 . num = = ( zend_ulong ) idx )
{
precv = op ;
}
+ + op ;
}
}
if ( precv & & precv - > opcode = = ZEND_RECV_INIT & & precv - > op2_type ! = IS_UNUSED ) {
2017-10-04 21:53:01 +08:00
zval * zv = RT_CONSTANT ( precv , precv - > op2 ) ;
2014-09-19 06:01:05 +08:00
2017-10-10 15:11:05 +08:00
if ( Z_TYPE_P ( zv ) = = IS_FALSE ) {
2014-09-21 05:27:10 +08:00
smart_str_appends ( & str , " false " ) ;
2014-09-19 06:01:05 +08:00
} else if ( Z_TYPE_P ( zv ) = = IS_TRUE ) {
2014-09-21 05:27:10 +08:00
smart_str_appends ( & str , " true " ) ;
2014-09-19 06:01:05 +08:00
} else if ( Z_TYPE_P ( zv ) = = IS_NULL ) {
2014-09-21 05:27:10 +08:00
smart_str_appends ( & str , " NULL " ) ;
2014-09-19 06:01:05 +08:00
} else if ( Z_TYPE_P ( zv ) = = IS_STRING ) {
2014-09-21 05:27:10 +08:00
smart_str_appendc ( & str , ' \' ' ) ;
smart_str_appendl ( & str , Z_STRVAL_P ( zv ) , MIN ( Z_STRLEN_P ( zv ) , 10 ) ) ;
2014-09-19 06:01:05 +08:00
if ( Z_STRLEN_P ( zv ) > 10 ) {
2014-09-21 05:27:10 +08:00
smart_str_appends ( & str , " ... " ) ;
2014-09-19 06:01:05 +08:00
}
2014-09-21 05:27:10 +08:00
smart_str_appendc ( & str , ' \' ' ) ;
2014-09-19 06:01:05 +08:00
} else if ( Z_TYPE_P ( zv ) = = IS_ARRAY ) {
2014-09-21 05:27:10 +08:00
smart_str_appends ( & str , " Array " ) ;
2014-09-19 06:01:05 +08:00
} else if ( Z_TYPE_P ( zv ) = = IS_CONSTANT_AST ) {
2017-10-10 15:11:05 +08:00
zend_ast * ast = Z_ASTVAL_P ( zv ) ;
if ( ast - > kind = = ZEND_AST_CONSTANT ) {
smart_str_append ( & str , zend_ast_get_constant_name ( ast ) ) ;
} else {
smart_str_appends ( & str , " <expression> " ) ;
}
2014-09-19 06:01:05 +08:00
} else {
2017-11-16 22:09:32 +08:00
zend_string * tmp_zv_str ;
zend_string * zv_str = zval_get_tmp_string ( zv , & tmp_zv_str ) ;
2014-09-22 02:47:07 +08:00
smart_str_append ( & str , zv_str ) ;
2017-11-16 22:09:32 +08:00
zend_tmp_string_release ( tmp_zv_str ) ;
2014-09-19 06:01:05 +08:00
}
}
} else {
2014-09-21 05:27:10 +08:00
smart_str_appends ( & str , " NULL " ) ;
2014-09-19 06:01:05 +08:00
}
}
2014-12-22 21:44:39 +08:00
if ( + + i < num_args ) {
2014-09-21 05:27:10 +08:00
smart_str_appends ( & str , " , " ) ;
2014-09-19 06:01:05 +08:00
}
arg_info + + ;
}
}
2014-09-21 05:27:10 +08:00
smart_str_appendc ( & str , ' ) ' ) ;
2015-01-09 04:40:36 +08:00
if ( fptr - > common . fn_flags & ZEND_ACC_HAS_RETURN_TYPE ) {
smart_str_appends ( & str , " : " ) ;
zend_append_type_hint ( & str , fptr , fptr - > common . arg_info - 1 , 1 ) ;
}
2014-09-21 05:27:10 +08:00
smart_str_0 ( & str ) ;
return str . s ;
2014-09-19 06:01:05 +08:00
}
/* }}} */
2014-12-14 06:06:14 +08:00
static void do_inheritance_check_on_method ( zend_function * child , zend_function * parent ) /* { { { */
2014-09-19 06:01:05 +08:00
{
uint32_t child_flags ;
uint32_t parent_flags = parent - > common . fn_flags ;
2015-03-05 07:10:38 +08:00
if ( UNEXPECTED ( parent_flags & ZEND_ACC_FINAL ) ) {
2015-06-30 18:59:27 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot override final method %s::%s() " , ZEND_FN_SCOPE_NAME ( parent ) , ZSTR_VAL ( child - > common . function_name ) ) ;
2014-09-19 06:01:05 +08:00
}
child_flags = child - > common . fn_flags ;
/* You cannot change from static to non static and vice versa.
*/
2015-03-05 07:10:38 +08:00
if ( UNEXPECTED ( ( child_flags & ZEND_ACC_STATIC ) ! = ( parent_flags & ZEND_ACC_STATIC ) ) ) {
2014-09-19 06:01:05 +08:00
if ( child - > common . fn_flags & ZEND_ACC_STATIC ) {
2015-06-30 18:59:27 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot make non static method %s::%s() static in class %s " , ZEND_FN_SCOPE_NAME ( parent ) , ZSTR_VAL ( child - > common . function_name ) , ZEND_FN_SCOPE_NAME ( child ) ) ;
2014-09-19 06:01:05 +08:00
} else {
2015-06-30 18:59:27 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot make static method %s::%s() non static in class %s " , ZEND_FN_SCOPE_NAME ( parent ) , ZSTR_VAL ( child - > common . function_name ) , ZEND_FN_SCOPE_NAME ( child ) ) ;
2014-09-19 06:01:05 +08:00
}
}
/* Disallow making an inherited method abstract. */
2015-03-05 07:10:38 +08:00
if ( UNEXPECTED ( ( child_flags & ZEND_ACC_ABSTRACT ) > ( parent_flags & ZEND_ACC_ABSTRACT ) ) ) {
2015-06-30 18:59:27 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot make non abstract method %s::%s() abstract in class %s " , ZEND_FN_SCOPE_NAME ( parent ) , ZSTR_VAL ( child - > common . function_name ) , ZEND_FN_SCOPE_NAME ( child ) ) ;
2014-09-19 06:01:05 +08:00
}
2017-03-11 03:08:15 +08:00
/* Prevent derived classes from restricting access that was available in parent classes (except deriving from non-abstract ctors) */
if ( UNEXPECTED ( ( ! ( child_flags & ZEND_ACC_CTOR ) | | ( parent_flags & ( ZEND_ACC_ABSTRACT | ZEND_ACC_IMPLEMENTED_ABSTRACT ) ) ) & &
( child_flags & ZEND_ACC_PPP_MASK ) > ( parent_flags & ZEND_ACC_PPP_MASK ) ) ) {
2016-03-30 01:07:14 +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 ) , ZSTR_VAL ( child - > common . function_name ) , zend_visibility_string ( parent_flags ) , ZEND_FN_SCOPE_NAME ( parent ) , ( parent_flags & ZEND_ACC_PUBLIC ) ? " " : " or weaker " ) ;
}
if ( ( ( child_flags & ZEND_ACC_PPP_MASK ) < ( parent_flags & ZEND_ACC_PPP_MASK ) )
& & ( ( parent_flags & ZEND_ACC_PPP_MASK ) & ZEND_ACC_PRIVATE ) ) {
child - > common . fn_flags | = ZEND_ACC_CHANGED ;
}
2014-09-19 06:01:05 +08:00
if ( parent_flags & ZEND_ACC_CHANGED ) {
child - > common . fn_flags | = ZEND_ACC_CHANGED ;
}
if ( parent_flags & ZEND_ACC_PRIVATE ) {
child - > common . prototype = NULL ;
} else if ( parent_flags & ZEND_ACC_ABSTRACT ) {
child - > common . fn_flags | = ZEND_ACC_IMPLEMENTED_ABSTRACT ;
child - > common . prototype = parent ;
} else if ( ! ( parent - > common . fn_flags & ZEND_ACC_CTOR ) | | ( parent - > common . prototype & & ( parent - > common . prototype - > common . scope - > ce_flags & ZEND_ACC_INTERFACE ) ) ) {
/* ctors only have a prototype if it comes from an interface */
child - > common . prototype = parent - > common . prototype ? parent - > common . prototype : parent ;
2017-01-27 06:50:56 +08:00
/* and if that is the case, we want to check inheritance against it */
if ( parent - > common . fn_flags & ZEND_ACC_CTOR ) {
parent = child - > common . prototype ;
}
2014-09-19 06:01:05 +08:00
}
2016-04-06 22:17:10 +08:00
if ( UNEXPECTED ( ! zend_do_perform_implementation_check ( child , parent ) ) ) {
int error_level ;
const char * error_verb ;
2016-04-07 04:25:05 +08:00
zend_string * method_prototype = zend_get_function_declaration ( parent ) ;
zend_string * child_prototype = zend_get_function_declaration ( child ) ;
2016-04-06 22:17:10 +08:00
if ( child - > common . prototype & & (
child - > common . prototype - > common . fn_flags & ZEND_ACC_ABSTRACT
) ) {
error_level = E_COMPILE_ERROR ;
error_verb = " must " ;
} else if ( ( parent - > common . fn_flags & ZEND_ACC_HAS_RETURN_TYPE ) & &
( ! ( child - > common . fn_flags & ZEND_ACC_HAS_RETURN_TYPE ) | |
2016-04-06 23:24:34 +08:00
! zend_do_perform_type_hint_check ( child , child - > common . arg_info - 1 , parent , parent - > common . arg_info - 1 ) | |
2017-01-13 16:37:46 +08:00
( ZEND_TYPE_ALLOW_NULL ( child - > common . arg_info [ - 1 ] . type ) & & ! ZEND_TYPE_ALLOW_NULL ( parent - > common . arg_info [ - 1 ] . type ) ) ) ) {
2016-04-06 22:17:10 +08:00
error_level = E_COMPILE_ERROR ;
error_verb = " must " ;
} else {
error_level = E_WARNING ;
error_verb = " should " ;
2014-09-19 06:01:05 +08:00
}
2016-04-06 22:17:10 +08:00
zend_error ( error_level , " Declaration of %s %s be compatible with %s " , ZSTR_VAL ( child_prototype ) , error_verb , ZSTR_VAL ( method_prototype ) ) ;
2015-06-29 06:28:52 +08:00
zend_string_free ( child_prototype ) ;
2015-03-15 16:47:25 +08:00
zend_string_free ( method_prototype ) ;
2014-09-19 06:01:05 +08:00
}
}
/* }}} */
2015-03-05 07:10:38 +08:00
static zend_function * do_inherit_method ( zend_string * key , zend_function * parent , zend_class_entry * ce ) /* { { { */
2014-09-19 06:01:05 +08:00
{
2015-03-05 07:10:38 +08:00
zval * child = zend_hash_find ( & ce - > function_table , key ) ;
2014-09-19 06:01:05 +08:00
2015-03-05 07:10:38 +08:00
if ( child ) {
2016-01-13 16:41:57 +08:00
zend_function * func = ( zend_function * ) Z_PTR_P ( child ) ;
zend_function * orig_prototype = func - > common . prototype ;
do_inheritance_check_on_method ( func , parent ) ;
if ( func - > common . prototype ! = orig_prototype & &
func - > type = = ZEND_USER_FUNCTION & &
func - > common . scope ! = ce & &
! func - > op_array . static_variables ) {
/* Lazy duplication */
zend_function * new_function = zend_arena_alloc ( & CG ( arena ) , sizeof ( zend_op_array ) ) ;
memcpy ( new_function , func , sizeof ( zend_op_array ) ) ;
Z_PTR_P ( child ) = new_function ;
func - > common . prototype = orig_prototype ;
}
2015-03-05 07:10:38 +08:00
return NULL ;
2014-09-19 06:01:05 +08:00
}
2015-03-05 07:10:38 +08:00
if ( parent - > common . fn_flags & ( ZEND_ACC_ABSTRACT ) ) {
ce - > ce_flags | = ZEND_ACC_IMPLICIT_ABSTRACT_CLASS ;
}
2014-09-19 06:01:05 +08:00
2015-03-05 07:10:38 +08:00
return zend_duplicate_function ( parent , ce ) ;
2014-09-19 06:01:05 +08:00
}
/* }}} */
2015-03-04 22:41:01 +08:00
static void do_inherit_property ( zend_property_info * parent_info , zend_string * key , zend_class_entry * ce ) /* { { { */
2014-09-19 06:01:05 +08:00
{
2015-03-05 04:06:07 +08:00
zval * child = zend_hash_find ( & ce - > properties_info , key ) ;
zend_property_info * child_info ;
2014-09-19 06:01:05 +08:00
2015-03-05 04:06:07 +08:00
if ( UNEXPECTED ( child ) ) {
child_info = Z_PTR_P ( child ) ;
2015-03-06 22:07:36 +08:00
if ( UNEXPECTED ( parent_info - > flags & ( ZEND_ACC_PRIVATE | ZEND_ACC_SHADOW ) ) ) {
2014-09-19 06:01:05 +08:00
child_info - > flags | = ZEND_ACC_CHANGED ;
} else {
2015-03-05 07:10:38 +08:00
if ( UNEXPECTED ( ( parent_info - > flags & ZEND_ACC_STATIC ) ! = ( child_info - > flags & ZEND_ACC_STATIC ) ) ) {
2015-03-04 22:41:01 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot redeclare %s%s::$%s as %s%s::$%s " ,
2015-06-30 18:59:27 +08:00
( parent_info - > flags & ZEND_ACC_STATIC ) ? " static " : " non static " , ZSTR_VAL ( ce - > parent - > name ) , ZSTR_VAL ( key ) ,
( child_info - > flags & ZEND_ACC_STATIC ) ? " static " : " non static " , ZSTR_VAL ( ce - > name ) , ZSTR_VAL ( key ) ) ;
2015-03-04 22:41:01 +08:00
}
if ( parent_info - > flags & ZEND_ACC_CHANGED ) {
child_info - > flags | = ZEND_ACC_CHANGED ;
}
2015-03-05 07:10:38 +08:00
if ( UNEXPECTED ( ( child_info - > flags & ZEND_ACC_PPP_MASK ) > ( parent_info - > flags & ZEND_ACC_PPP_MASK ) ) ) {
2015-06-30 18:59:27 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Access level to %s::$%s must be %s (as in class %s)%s " , ZSTR_VAL ( ce - > name ) , ZSTR_VAL ( key ) , zend_visibility_string ( parent_info - > flags ) , ZSTR_VAL ( ce - > parent - > name ) , ( parent_info - > flags & ZEND_ACC_PUBLIC ) ? " " : " or weaker " ) ;
2015-03-04 22:41:01 +08:00
} else if ( ( child_info - > flags & ZEND_ACC_STATIC ) = = 0 ) {
int parent_num = OBJ_PROP_TO_NUM ( parent_info - > offset ) ;
int child_num = OBJ_PROP_TO_NUM ( child_info - > offset ) ;
2016-05-06 14:48:58 +08:00
/* Don't keep default properties in GC (they may be freed by opcache) */
2016-04-19 06:37:24 +08:00
zval_ptr_dtor_nogc ( & ( ce - > default_properties_table [ parent_num ] ) ) ;
2015-03-04 22:41:01 +08:00
ce - > default_properties_table [ parent_num ] = ce - > default_properties_table [ child_num ] ;
ZVAL_UNDEF ( & ce - > default_properties_table [ child_num ] ) ;
child_info - > offset = parent_info - > offset ;
}
}
} else {
2015-03-06 22:07:36 +08:00
if ( UNEXPECTED ( parent_info - > flags & ( ZEND_ACC_PRIVATE | ZEND_ACC_SHADOW ) ) ) {
if ( UNEXPECTED ( ce - > type & ZEND_INTERNAL_CLASS ) ) {
2014-09-19 06:01:05 +08:00
child_info = zend_duplicate_property_info_internal ( parent_info ) ;
} else {
2014-12-14 06:06:14 +08:00
child_info = zend_duplicate_property_info ( parent_info ) ;
2014-09-19 06:01:05 +08:00
}
child_info - > flags & = ~ ZEND_ACC_PRIVATE ; /* it's not private anymore */
child_info - > flags | = ZEND_ACC_SHADOW ; /* but it's a shadow of private */
2015-03-04 22:41:01 +08:00
} else {
2015-03-06 22:07:36 +08:00
if ( UNEXPECTED ( ce - > type & ZEND_INTERNAL_CLASS ) ) {
2015-03-04 22:41:01 +08:00
child_info = zend_duplicate_property_info_internal ( parent_info ) ;
} else {
child_info = parent_info ;
}
2014-09-19 06:01:05 +08:00
}
2015-03-04 22:41:01 +08:00
_zend_hash_append_ptr ( & ce - > properties_info , key , child_info ) ;
2014-09-19 06:01:05 +08:00
}
}
/* }}} */
2014-12-14 06:06:14 +08:00
static inline void do_implement_interface ( zend_class_entry * ce , zend_class_entry * iface ) /* { { { */
2014-09-19 06:01:05 +08:00
{
2014-12-14 06:06:14 +08:00
if ( ! ( ce - > ce_flags & ZEND_ACC_INTERFACE ) & & iface - > interface_gets_implemented & & iface - > interface_gets_implemented ( iface , ce ) = = FAILURE ) {
2015-06-30 18:59:27 +08:00
zend_error_noreturn ( E_CORE_ERROR , " Class %s could not implement interface %s " , ZSTR_VAL ( ce - > name ) , ZSTR_VAL ( iface - > name ) ) ;
2014-09-19 06:01:05 +08:00
}
2015-03-05 07:10:38 +08:00
if ( UNEXPECTED ( ce = = iface ) ) {
2015-06-30 18:59:27 +08:00
zend_error_noreturn ( E_ERROR , " Interface %s cannot implement itself " , ZSTR_VAL ( ce - > name ) ) ;
2014-09-19 06:01:05 +08:00
}
}
/* }}} */
2014-12-14 06:06:14 +08:00
ZEND_API void zend_do_inherit_interfaces ( zend_class_entry * ce , const zend_class_entry * iface ) /* { { { */
2014-09-19 06:01:05 +08:00
{
/* expects interface to be contained in ce's interface list already */
uint32_t i , ce_num , if_num = iface - > num_interfaces ;
zend_class_entry * entry ;
if ( if_num = = 0 ) {
return ;
}
ce_num = ce - > num_interfaces ;
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 ;
}
}
if ( i = = ce_num ) {
ce - > interfaces [ ce - > num_interfaces + + ] = entry ;
}
}
/* and now call the implementing handlers */
while ( ce_num < ce - > num_interfaces ) {
2014-12-14 06:06:14 +08:00
do_implement_interface ( ce , ce - > interfaces [ ce_num + + ] ) ;
2014-09-19 06:01:05 +08:00
}
}
/* }}} */
2015-12-08 17:40:42 +08:00
static void do_inherit_class_constant ( zend_string * name , zend_class_constant * parent_const , zend_class_entry * ce ) /* { { { */
2014-09-19 06:01:05 +08:00
{
2015-12-08 17:40:42 +08:00
zend_class_constant * c = zend_hash_find_ptr ( & ce - > constants_table , name ) ;
if ( c ! = NULL ) {
if ( UNEXPECTED ( ( Z_ACCESS_FLAGS ( c - > value ) & ZEND_ACC_PPP_MASK ) > ( Z_ACCESS_FLAGS ( parent_const - > value ) & ZEND_ACC_PPP_MASK ) ) ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Access level to %s::%s must be %s (as in class %s)%s " ,
ZSTR_VAL ( ce - > name ) , ZSTR_VAL ( name ) , zend_visibility_string ( Z_ACCESS_FLAGS ( parent_const - > value ) ) , ZSTR_VAL ( ce - > parent - > name ) , ( Z_ACCESS_FLAGS ( parent_const - > value ) & ZEND_ACC_PUBLIC ) ? " " : " or weaker " ) ;
2015-03-05 04:06:07 +08:00
}
2015-12-08 17:40:42 +08:00
} else if ( ! ( Z_ACCESS_FLAGS ( parent_const - > value ) & ZEND_ACC_PRIVATE ) ) {
2017-10-10 15:11:05 +08:00
if ( Z_TYPE ( parent_const - > value ) = = IS_CONSTANT_AST ) {
2015-03-05 04:06:07 +08:00
ce - > ce_flags & = ~ ZEND_ACC_CONSTANTS_UPDATED ;
2014-09-19 06:01:05 +08:00
}
2017-10-31 06:20:38 +08:00
if ( ce - > type & ZEND_INTERNAL_CLASS ) {
c = pemalloc ( sizeof ( zend_class_constant ) , 1 ) ;
memcpy ( c , parent_const , sizeof ( zend_class_constant ) ) ;
parent_const = c ;
}
2017-10-31 04:13:10 +08:00
_zend_hash_append_ptr ( & ce - > constants_table , name , parent_const ) ;
2014-09-19 06:01:05 +08:00
}
}
/* }}} */
2014-12-14 06:06:14 +08:00
ZEND_API void zend_do_inheritance ( zend_class_entry * ce , zend_class_entry * parent_ce ) /* { { { */
2014-09-19 06:01:05 +08:00
{
zend_property_info * property_info ;
zend_function * func ;
zend_string * key ;
2015-03-05 07:10:38 +08:00
if ( UNEXPECTED ( ce - > ce_flags & ZEND_ACC_INTERFACE ) ) {
2014-12-06 12:42:52 +08:00
/* Interface can only inherit other interfaces */
2015-03-05 07:10:38 +08:00
if ( UNEXPECTED ( ! ( parent_ce - > ce_flags & ZEND_ACC_INTERFACE ) ) ) {
2015-06-30 18:59:27 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Interface %s may not inherit from class (%s) " , ZSTR_VAL ( ce - > name ) , ZSTR_VAL ( parent_ce - > name ) ) ;
2014-12-06 12:42:52 +08:00
}
2015-03-05 04:06:07 +08:00
} else if ( UNEXPECTED ( parent_ce - > ce_flags & ( ZEND_ACC_INTERFACE | ZEND_ACC_TRAIT | ZEND_ACC_FINAL ) ) ) {
2014-12-06 12:42:52 +08:00
/* Class declaration must not extend traits or interfaces */
if ( parent_ce - > ce_flags & ZEND_ACC_INTERFACE ) {
2015-06-30 18:59:27 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Class %s cannot extend from interface %s " , ZSTR_VAL ( ce - > name ) , ZSTR_VAL ( parent_ce - > name ) ) ;
2014-12-06 12:42:52 +08:00
} else if ( parent_ce - > ce_flags & ZEND_ACC_TRAIT ) {
2015-06-30 18:59:27 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Class %s cannot extend from trait %s " , ZSTR_VAL ( ce - > name ) , ZSTR_VAL ( parent_ce - > name ) ) ;
2014-12-06 12:42:52 +08:00
}
/* Class must not extend a final class */
if ( parent_ce - > ce_flags & ZEND_ACC_FINAL ) {
2015-06-30 18:59:27 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Class %s may not inherit from final class (%s) " , ZSTR_VAL ( ce - > name ) , ZSTR_VAL ( parent_ce - > name ) ) ;
2014-12-06 12:42:52 +08:00
}
2014-09-19 06:01:05 +08:00
}
ce - > parent = parent_ce ;
2014-12-06 12:42:52 +08:00
2014-09-19 06:01:05 +08:00
/* Inherit interfaces */
2014-12-14 06:06:14 +08:00
zend_do_inherit_interfaces ( ce , parent_ce ) ;
2014-09-19 06:01:05 +08:00
/* Inherit properties */
if ( parent_ce - > default_properties_count ) {
2015-04-22 17:53:54 +08:00
zval * src , * dst , * end ;
2014-09-19 06:01:05 +08:00
if ( ce - > default_properties_count ) {
2015-04-22 17:53:54 +08:00
zval * table = pemalloc ( sizeof ( zval ) * ( ce - > default_properties_count + parent_ce - > default_properties_count ) , ce - > type = = ZEND_INTERNAL_CLASS ) ;
src = ce - > default_properties_table + ce - > default_properties_count ;
end = table + parent_ce - > default_properties_count ;
dst = end + ce - > default_properties_count ;
ce - > default_properties_table = table ;
do {
dst - - ;
src - - ;
ZVAL_COPY_VALUE ( dst , src ) ;
} while ( dst ! = end ) ;
pefree ( src , ce - > type = = ZEND_INTERNAL_CLASS ) ;
end = ce - > default_properties_table ;
} else {
end = pemalloc ( sizeof ( zval ) * parent_ce - > default_properties_count , ce - > type = = ZEND_INTERNAL_CLASS ) ;
dst = end + parent_ce - > default_properties_count ;
ce - > default_properties_table = end ;
}
src = parent_ce - > default_properties_table + parent_ce - > default_properties_count ;
2017-10-31 04:13:10 +08:00
if ( UNEXPECTED ( parent_ce - > type ! = ce - > type ) ) {
/* User class extends internal */
do {
dst - - ;
src - - ;
ZVAL_COPY_OR_DUP ( dst , src ) ;
2017-10-10 15:11:05 +08:00
if ( Z_OPT_TYPE_P ( dst ) = = IS_CONSTANT_AST ) {
2014-09-19 06:01:05 +08:00
ce - > ce_flags & = ~ ZEND_ACC_CONSTANTS_UPDATED ;
}
continue ;
2017-10-31 04:13:10 +08:00
} while ( dst ! = end ) ;
} else {
do {
dst - - ;
src - - ;
ZVAL_COPY ( dst , src ) ;
if ( Z_OPT_TYPE_P ( dst ) = = IS_CONSTANT_AST ) {
ce - > ce_flags & = ~ ZEND_ACC_CONSTANTS_UPDATED ;
}
continue ;
} while ( dst ! = end ) ;
}
2014-09-19 06:01:05 +08:00
ce - > default_properties_count + = parent_ce - > default_properties_count ;
}
2015-04-22 17:53:54 +08:00
if ( parent_ce - > default_static_members_count ) {
zval * src , * dst , * end ;
if ( ce - > default_static_members_count ) {
zval * table = pemalloc ( sizeof ( zval ) * ( ce - > default_static_members_count + parent_ce - > default_static_members_count ) , ce - > type = = ZEND_INTERNAL_CLASS ) ;
src = ce - > default_static_members_table + ce - > default_static_members_count ;
end = table + parent_ce - > default_static_members_count ;
dst = end + ce - > default_static_members_count ;
ce - > default_static_members_table = table ;
do {
dst - - ;
src - - ;
ZVAL_COPY_VALUE ( dst , src ) ;
} while ( dst ! = end ) ;
pefree ( src , ce - > type = = ZEND_INTERNAL_CLASS ) ;
end = ce - > default_static_members_table ;
} else {
end = pemalloc ( sizeof ( zval ) * parent_ce - > default_static_members_count , ce - > type = = ZEND_INTERNAL_CLASS ) ;
dst = end + parent_ce - > default_static_members_count ;
ce - > default_static_members_table = end ;
}
2017-10-31 04:13:10 +08:00
if ( UNEXPECTED ( parent_ce - > type ! = ce - > type ) ) {
/* User class extends internal */
if ( UNEXPECTED ( zend_update_class_constants ( parent_ce ) ! = SUCCESS ) ) {
ZEND_ASSERT ( 0 ) ;
}
src = CE_STATIC_MEMBERS ( parent_ce ) + parent_ce - > default_static_members_count ;
do {
dst - - ;
src - - ;
ZVAL_MAKE_REF ( src ) ;
ZVAL_COPY_VALUE ( dst , src ) ;
Z_ADDREF_P ( dst ) ;
} while ( dst ! = end ) ;
} else if ( ce - > type = = ZEND_USER_CLASS ) {
src = parent_ce - > default_static_members_table + parent_ce - > default_static_members_count ;
do {
dst - - ;
src - - ;
ZVAL_MAKE_REF ( src ) ;
ZVAL_COPY_VALUE ( dst , src ) ;
Z_ADDREF_P ( dst ) ;
if ( Z_TYPE_P ( Z_REFVAL_P ( dst ) ) = = IS_CONSTANT_AST ) {
ce - > ce_flags & = ~ ZEND_ACC_CONSTANTS_UPDATED ;
}
} while ( dst ! = end ) ;
} else {
src = parent_ce - > default_static_members_table + parent_ce - > default_static_members_count ;
do {
dst - - ;
src - - ;
2015-07-10 15:27:06 +08:00
if ( ! Z_ISREF_P ( src ) ) {
ZVAL_NEW_PERSISTENT_REF ( src , src ) ;
}
2017-10-31 04:13:10 +08:00
ZVAL_COPY_VALUE ( dst , src ) ;
Z_ADDREF_P ( dst ) ;
} while ( dst ! = end ) ;
}
2015-04-22 17:53:54 +08:00
ce - > default_static_members_count + = parent_ce - > default_static_members_count ;
if ( ce - > type = = ZEND_USER_CLASS ) {
2014-09-19 06:01:05 +08:00
ce - > static_members_table = ce - > default_static_members_table ;
2015-07-10 16:04:45 +08:00
} else {
ce - > ce_flags & = ~ ZEND_ACC_CONSTANTS_UPDATED ;
2014-09-19 06:01:05 +08:00
}
}
ZEND_HASH_FOREACH_PTR ( & ce - > properties_info , property_info ) {
if ( property_info - > ce = = ce ) {
if ( property_info - > flags & ZEND_ACC_STATIC ) {
property_info - > offset + = parent_ce - > default_static_members_count ;
} else {
2014-11-06 19:50:03 +08:00
property_info - > offset + = parent_ce - > default_properties_count * sizeof ( zval ) ;
2014-09-19 06:01:05 +08:00
}
}
} ZEND_HASH_FOREACH_END ( ) ;
2015-03-05 04:06:07 +08:00
if ( zend_hash_num_elements ( & parent_ce - > properties_info ) ) {
zend_hash_extend ( & ce - > properties_info ,
zend_hash_num_elements ( & ce - > properties_info ) +
zend_hash_num_elements ( & parent_ce - > properties_info ) , 0 ) ;
2015-03-04 22:41:01 +08:00
2015-03-05 04:06:07 +08:00
ZEND_HASH_FOREACH_STR_KEY_PTR ( & parent_ce - > properties_info , key , property_info ) {
do_inherit_property ( property_info , key , ce ) ;
} ZEND_HASH_FOREACH_END ( ) ;
}
2014-09-19 06:01:05 +08:00
2015-03-05 04:06:07 +08:00
if ( zend_hash_num_elements ( & parent_ce - > constants_table ) ) {
2015-12-08 17:40:42 +08:00
zend_class_constant * c ;
2015-03-05 04:06:07 +08:00
zend_hash_extend ( & ce - > constants_table ,
zend_hash_num_elements ( & ce - > constants_table ) +
zend_hash_num_elements ( & parent_ce - > constants_table ) , 0 ) ;
2014-09-19 06:01:05 +08:00
2015-12-08 17:40:42 +08:00
ZEND_HASH_FOREACH_STR_KEY_PTR ( & parent_ce - > constants_table , key , c ) {
do_inherit_class_constant ( key , c , ce ) ;
2015-03-05 04:06:07 +08:00
} ZEND_HASH_FOREACH_END ( ) ;
}
if ( zend_hash_num_elements ( & parent_ce - > function_table ) ) {
zend_hash_extend ( & ce - > function_table ,
zend_hash_num_elements ( & ce - > function_table ) +
zend_hash_num_elements ( & parent_ce - > function_table ) , 0 ) ;
ZEND_HASH_FOREACH_STR_KEY_PTR ( & parent_ce - > function_table , key , func ) {
2015-03-05 07:10:38 +08:00
zend_function * new_func = do_inherit_method ( key , func , ce ) ;
if ( new_func ) {
2015-03-05 04:06:07 +08:00
_zend_hash_append_ptr ( & ce - > function_table , key , new_func ) ;
}
} ZEND_HASH_FOREACH_END ( ) ;
}
2014-09-19 06:01:05 +08:00
2014-12-14 06:06:14 +08:00
do_inherit_parent_constructor ( ce ) ;
2014-09-19 06:01:05 +08:00
if ( ce - > ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS & & ce - > type = = ZEND_INTERNAL_CLASS ) {
ce - > ce_flags | = ZEND_ACC_EXPLICIT_ABSTRACT_CLASS ;
} else if ( ! ( ce - > ce_flags & ( ZEND_ACC_IMPLEMENT_INTERFACES | ZEND_ACC_IMPLEMENT_TRAITS ) ) ) {
/* The verification will be done in runtime by ZEND_VERIFY_ABSTRACT_CLASS */
2014-12-14 06:06:14 +08:00
zend_verify_abstract_class ( ce ) ;
2014-09-19 06:01:05 +08:00
}
2015-02-04 20:24:13 +08:00
ce - > ce_flags | = parent_ce - > ce_flags & ( ZEND_HAS_STATIC_IN_METHODS | ZEND_ACC_USE_GUARDS ) ;
2014-09-19 06:01:05 +08:00
}
/* }}} */
2015-12-08 17:40:42 +08:00
static zend_bool do_inherit_constant_check ( HashTable * child_constants_table , zend_class_constant * parent_constant , zend_string * name , const zend_class_entry * iface ) /* { { { */
2014-09-19 06:01:05 +08:00
{
2015-12-08 17:40:42 +08:00
zend_class_constant * old_constant ;
2014-09-19 06:01:05 +08:00
2015-12-08 17:40:42 +08:00
if ( ( old_constant = zend_hash_find_ptr ( child_constants_table , name ) ) ! = NULL ) {
if ( old_constant - > ce ! = parent_constant - > ce ) {
2015-06-30 18:59:27 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot inherit previously-inherited or override constant %s from interface %s " , ZSTR_VAL ( name ) , ZSTR_VAL ( iface - > name ) ) ;
2014-09-19 06:01:05 +08:00
}
return 0 ;
}
return 1 ;
}
/* }}} */
2015-12-08 17:40:42 +08:00
static void do_inherit_iface_constant ( zend_string * name , zend_class_constant * c , zend_class_entry * ce , zend_class_entry * iface ) /* { { { */
2014-09-19 06:01:05 +08:00
{
2015-12-08 17:40:42 +08:00
if ( do_inherit_constant_check ( & ce - > constants_table , c , name , iface ) ) {
2016-01-21 13:30:41 +08:00
zend_class_constant * ct ;
2017-10-10 15:11:05 +08:00
if ( Z_TYPE ( c - > value ) = = IS_CONSTANT_AST ) {
2014-09-19 06:01:05 +08:00
ce - > ce_flags & = ~ ZEND_ACC_CONSTANTS_UPDATED ;
}
2017-10-31 06:20:38 +08:00
if ( ce - > type & ZEND_INTERNAL_CLASS ) {
ct = pemalloc ( sizeof ( zend_class_constant ) , 1 ) ;
memcpy ( ct , c , sizeof ( zend_class_constant ) ) ;
c = ct ;
}
2017-10-31 04:13:10 +08:00
zend_hash_update_ptr ( & ce - > constants_table , name , c ) ;
2014-09-19 06:01:05 +08:00
}
}
/* }}} */
2014-12-14 06:06:14 +08:00
ZEND_API void zend_do_implement_interface ( zend_class_entry * ce , zend_class_entry * iface ) /* { { { */
2014-09-19 06:01:05 +08:00
{
uint32_t i , ignore = 0 ;
uint32_t current_iface_num = ce - > num_interfaces ;
uint32_t parent_iface_num = ce - > parent ? ce - > parent - > num_interfaces : 0 ;
zend_function * func ;
zend_string * key ;
2015-12-08 17:40:42 +08:00
zend_class_constant * c ;
2014-09-19 06:01:05 +08:00
for ( i = 0 ; i < ce - > num_interfaces ; i + + ) {
if ( ce - > interfaces [ i ] = = NULL ) {
memmove ( ce - > interfaces + i , ce - > interfaces + i + 1 , sizeof ( zend_class_entry * ) * ( - - ce - > num_interfaces - i ) ) ;
i - - ;
} else if ( ce - > interfaces [ i ] = = iface ) {
2015-03-05 07:10:38 +08:00
if ( EXPECTED ( i < parent_iface_num ) ) {
2014-09-19 06:01:05 +08:00
ignore = 1 ;
} else {
2015-06-30 18:59:27 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Class %s cannot implement previously implemented interface %s " , ZSTR_VAL ( ce - > name ) , ZSTR_VAL ( iface - > name ) ) ;
2014-09-19 06:01:05 +08:00
}
}
}
if ( ignore ) {
/* Check for attempt to redeclare interface constants */
2015-12-08 17:40:42 +08:00
ZEND_HASH_FOREACH_STR_KEY_PTR ( & ce - > constants_table , key , c ) {
do_inherit_constant_check ( & iface - > constants_table , c , key , iface ) ;
2014-09-19 06:01:05 +08:00
} ZEND_HASH_FOREACH_END ( ) ;
} else {
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 ;
2015-12-08 17:40:42 +08:00
ZEND_HASH_FOREACH_STR_KEY_PTR ( & iface - > constants_table , key , c ) {
do_inherit_iface_constant ( key , c , ce , iface ) ;
2014-09-19 06:01:05 +08:00
} ZEND_HASH_FOREACH_END ( ) ;
ZEND_HASH_FOREACH_STR_KEY_PTR ( & iface - > function_table , key , func ) {
2015-03-05 07:10:38 +08:00
zend_function * new_func = do_inherit_method ( key , func , ce ) ;
if ( new_func ) {
2014-09-19 06:01:05 +08:00
zend_hash_add_new_ptr ( & ce - > function_table , key , new_func ) ;
}
} ZEND_HASH_FOREACH_END ( ) ;
2014-12-14 06:06:14 +08:00
do_implement_interface ( ce , iface ) ;
zend_do_inherit_interfaces ( ce , iface ) ;
2014-09-19 06:01:05 +08:00
}
}
/* }}} */
2014-12-14 06:06:14 +08:00
ZEND_API void zend_do_implement_trait ( zend_class_entry * ce , zend_class_entry * trait ) /* { { { */
2014-09-19 06:01:05 +08:00
{
uint32_t i , ignore = 0 ;
uint32_t current_trait_num = ce - > num_traits ;
uint32_t 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 ;
}
}
/* }}} */
2014-12-14 06:06:14 +08:00
static zend_bool zend_traits_method_compatibility_check ( zend_function * fn , zend_function * other_fn ) /* { { { */
2014-09-19 06:01:05 +08:00
{
uint32_t fn_flags = fn - > common . scope - > ce_flags ;
uint32_t other_flags = other_fn - > common . scope - > ce_flags ;
2014-12-14 06:06:14 +08:00
return zend_do_perform_implementation_check ( fn , other_fn )
2014-09-19 06:01:05 +08:00
& & ( ( fn_flags & ( ZEND_ACC_FINAL | ZEND_ACC_STATIC ) ) = =
( other_flags & ( ZEND_ACC_FINAL | ZEND_ACC_STATIC ) ) ) ; /* equal final and static qualifier */
}
/* }}} */
2014-12-14 06:06:14 +08:00
static void zend_add_magic_methods ( zend_class_entry * ce , zend_string * mname , zend_function * fe ) /* { { { */
2014-09-19 06:01:05 +08:00
{
2016-01-05 23:27:18 +08:00
if ( zend_string_equals_literal ( mname , ZEND_CLONE_FUNC_NAME ) ) {
2017-04-22 21:44:24 +08:00
ce - > clone = fe ;
2016-01-05 23:27:18 +08:00
} else if ( zend_string_equals_literal ( mname , ZEND_CONSTRUCTOR_FUNC_NAME ) ) {
2014-12-12 23:14:24 +08:00
if ( ce - > constructor & & ( ! ce - > parent | | ce - > constructor ! = ce - > parent - > constructor ) ) {
2015-06-30 18:59:27 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " %s has colliding constructor definitions coming from traits " , ZSTR_VAL ( ce - > name ) ) ;
2014-09-19 06:01:05 +08:00
}
ce - > constructor = fe ; fe - > common . fn_flags | = ZEND_ACC_CTOR ;
2016-01-05 23:27:18 +08:00
} else if ( zend_string_equals_literal ( mname , ZEND_DESTRUCTOR_FUNC_NAME ) ) {
2014-09-19 06:01:05 +08:00
ce - > destructor = fe ; fe - > common . fn_flags | = ZEND_ACC_DTOR ;
2016-01-05 23:27:18 +08:00
} else if ( zend_string_equals_literal ( mname , ZEND_GET_FUNC_NAME ) ) {
2014-09-19 06:01:05 +08:00
ce - > __get = fe ;
2015-02-04 20:24:13 +08:00
ce - > ce_flags | = ZEND_ACC_USE_GUARDS ;
2016-01-05 23:27:18 +08:00
} else if ( zend_string_equals_literal ( mname , ZEND_SET_FUNC_NAME ) ) {
2014-09-19 06:01:05 +08:00
ce - > __set = fe ;
2015-02-04 20:24:13 +08:00
ce - > ce_flags | = ZEND_ACC_USE_GUARDS ;
2016-01-05 23:27:18 +08:00
} else if ( zend_string_equals_literal ( mname , ZEND_CALL_FUNC_NAME ) ) {
2014-09-19 06:01:05 +08:00
ce - > __call = fe ;
2016-01-05 23:27:18 +08:00
} else if ( zend_string_equals_literal ( mname , ZEND_UNSET_FUNC_NAME ) ) {
2014-09-19 06:01:05 +08:00
ce - > __unset = fe ;
2015-02-04 20:24:13 +08:00
ce - > ce_flags | = ZEND_ACC_USE_GUARDS ;
2016-01-05 23:27:18 +08:00
} else if ( zend_string_equals_literal ( mname , ZEND_ISSET_FUNC_NAME ) ) {
2014-09-19 06:01:05 +08:00
ce - > __isset = fe ;
2015-02-04 20:24:13 +08:00
ce - > ce_flags | = ZEND_ACC_USE_GUARDS ;
2016-01-05 23:27:18 +08:00
} else if ( zend_string_equals_literal ( mname , ZEND_CALLSTATIC_FUNC_NAME ) ) {
2014-09-19 06:01:05 +08:00
ce - > __callstatic = fe ;
2016-01-05 23:27:18 +08:00
} else if ( zend_string_equals_literal ( mname , ZEND_TOSTRING_FUNC_NAME ) ) {
2014-09-19 06:01:05 +08:00
ce - > __tostring = fe ;
2016-01-05 23:27:18 +08:00
} else if ( zend_string_equals_literal ( mname , ZEND_DEBUGINFO_FUNC_NAME ) ) {
2014-09-19 06:01:05 +08:00
ce - > __debugInfo = fe ;
2015-06-30 18:59:27 +08:00
} else if ( ZSTR_LEN ( ce - > name ) = = ZSTR_LEN ( mname ) ) {
2014-12-24 20:04:51 +08:00
zend_string * lowercase_name = zend_string_tolower ( ce - > name ) ;
2014-12-14 06:06:14 +08:00
lowercase_name = zend_new_interned_string ( lowercase_name ) ;
2015-06-30 18:59:27 +08:00
if ( ! memcmp ( ZSTR_VAL ( mname ) , ZSTR_VAL ( lowercase_name ) , ZSTR_LEN ( mname ) ) ) {
2014-12-12 23:14:24 +08:00
if ( ce - > constructor & & ( ! ce - > parent | | ce - > constructor ! = ce - > parent - > constructor ) ) {
2015-06-30 18:59:27 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " %s has colliding constructor definitions coming from traits " , ZSTR_VAL ( ce - > name ) ) ;
2014-09-19 06:01:05 +08:00
}
ce - > constructor = fe ;
fe - > common . fn_flags | = ZEND_ACC_CTOR ;
}
zend_string_release ( lowercase_name ) ;
}
}
/* }}} */
2014-12-14 06:06:14 +08:00
static void zend_add_trait_method ( zend_class_entry * ce , const char * name , zend_string * key , zend_function * fn , HashTable * * overriden ) /* { { { */
2014-09-19 06:01:05 +08:00
{
zend_function * existing_fn = NULL ;
zend_function * new_fn ;
if ( ( existing_fn = zend_hash_find_ptr ( & ce - > function_table , key ) ) ! = NULL ) {
if ( existing_fn - > common . scope = = ce ) {
/* members from the current class override trait methods */
/* use temporary *overriden HashTable to detect hidden conflict */
if ( * overriden ) {
if ( ( existing_fn = zend_hash_find_ptr ( * overriden , key ) ) ! = NULL ) {
if ( existing_fn - > common . fn_flags & ZEND_ACC_ABSTRACT ) {
/* Make sure the trait method is compatible with previosly declared abstract method */
2015-03-05 07:10:38 +08:00
if ( UNEXPECTED ( ! zend_traits_method_compatibility_check ( fn , existing_fn ) ) ) {
2014-09-19 06:01:05 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Declaration of %s must be compatible with %s " ,
2015-06-30 18:59:27 +08:00
ZSTR_VAL ( zend_get_function_declaration ( fn ) ) ,
ZSTR_VAL ( zend_get_function_declaration ( existing_fn ) ) ) ;
2014-09-19 06:01:05 +08:00
}
2017-05-21 20:41:55 +08:00
}
if ( fn - > common . fn_flags & ZEND_ACC_ABSTRACT ) {
2014-09-19 06:01:05 +08:00
/* Make sure the abstract declaration is compatible with previous declaration */
2015-03-05 07:10:38 +08:00
if ( UNEXPECTED ( ! zend_traits_method_compatibility_check ( existing_fn , fn ) ) ) {
2014-09-19 06:01:05 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Declaration of %s must be compatible with %s " ,
2017-05-21 20:41:55 +08:00
ZSTR_VAL ( zend_get_function_declaration ( existing_fn ) ) ,
ZSTR_VAL ( zend_get_function_declaration ( fn ) ) ) ;
2014-09-19 06:01:05 +08:00
}
return ;
}
}
} else {
ALLOC_HASHTABLE ( * overriden ) ;
2015-08-12 11:15:09 +08:00
zend_hash_init_ex ( * overriden , 8 , NULL , overriden_ptr_dtor , 0 , 0 ) ;
2014-09-19 06:01:05 +08:00
}
zend_hash_update_mem ( * overriden , key , fn , sizeof ( zend_function ) ) ;
return ;
2015-04-21 22:39:46 +08:00
} else if ( existing_fn - > common . fn_flags & ZEND_ACC_ABSTRACT & &
( existing_fn - > common . scope - > ce_flags & ZEND_ACC_INTERFACE ) = = 0 ) {
2014-09-19 06:01:05 +08:00
/* Make sure the trait method is compatible with previosly declared abstract method */
2015-03-05 07:10:38 +08:00
if ( UNEXPECTED ( ! zend_traits_method_compatibility_check ( fn , existing_fn ) ) ) {
2014-09-19 06:01:05 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Declaration of %s must be compatible with %s " ,
2015-06-30 18:59:27 +08:00
ZSTR_VAL ( zend_get_function_declaration ( fn ) ) ,
ZSTR_VAL ( zend_get_function_declaration ( existing_fn ) ) ) ;
2014-09-19 06:01:05 +08:00
}
} else if ( fn - > common . fn_flags & ZEND_ACC_ABSTRACT ) {
/* Make sure the abstract declaration is compatible with previous declaration */
2015-03-05 07:10:38 +08:00
if ( UNEXPECTED ( ! zend_traits_method_compatibility_check ( existing_fn , fn ) ) ) {
2014-09-19 06:01:05 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Declaration of %s must be compatible with %s " ,
2017-05-21 20:41:55 +08:00
ZSTR_VAL ( zend_get_function_declaration ( existing_fn ) ) ,
ZSTR_VAL ( zend_get_function_declaration ( fn ) ) ) ;
2014-09-19 06:01:05 +08:00
}
return ;
2015-03-05 07:10:38 +08:00
} else if ( UNEXPECTED ( existing_fn - > common . scope - > ce_flags & ZEND_ACC_TRAIT ) ) {
2014-09-19 06:01:05 +08:00
/* two traits can't define the same non-abstract method */
# if 1
zend_error_noreturn ( E_COMPILE_ERROR , " Trait method %s has not been applied, because there are collisions with other trait methods on %s " ,
2015-06-30 18:59:27 +08:00
name , ZSTR_VAL ( ce - > name ) ) ;
2014-09-19 06:01:05 +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 " ,
2015-06-30 18:59:27 +08:00
ZSTR_VAL ( fn - > common . scope - > name ) , ZSTR_VAL ( fn - > common . function_name ) ,
ZSTR_VAL ( ce - > name ) , name ,
ZSTR_VAL ( existing_fn - > common . scope - > name ) , ZSTR_VAL ( existing_fn - > common . function_name ) ) ;
2014-09-19 06:01:05 +08:00
# endif
} else {
/* inherited members are overridden by members inserted by traits */
/* check whether the trait method fulfills the inheritance requirements */
2014-12-14 06:06:14 +08:00
do_inheritance_check_on_method ( fn , existing_fn ) ;
2015-04-10 22:50:15 +08:00
fn - > common . prototype = NULL ;
2014-09-19 06:01:05 +08:00
}
}
function_add_ref ( fn ) ;
new_fn = zend_arena_alloc ( & CG ( arena ) , sizeof ( zend_op_array ) ) ;
memcpy ( new_fn , fn , sizeof ( zend_op_array ) ) ;
2016-09-22 11:09:45 +08:00
new_fn - > common . fn_flags | = ZEND_ACC_ARENA_ALLOCATED ;
2014-09-19 06:01:05 +08:00
fn = zend_hash_update_ptr ( & ce - > function_table , key , new_fn ) ;
2014-12-14 06:06:14 +08:00
zend_add_magic_methods ( ce , key , fn ) ;
2014-09-19 06:01:05 +08:00
}
/* }}} */
static void zend_fixup_trait_method ( zend_function * fn , zend_class_entry * ce ) /* { { { */
{
if ( ( fn - > common . scope - > ce_flags & ZEND_ACC_TRAIT ) = = ZEND_ACC_TRAIT ) {
fn - > common . scope = ce ;
if ( fn - > common . fn_flags & ZEND_ACC_ABSTRACT ) {
ce - > ce_flags | = ZEND_ACC_IMPLICIT_ABSTRACT_CLASS ;
}
2015-05-04 10:35:55 +08:00
if ( fn - > type = = ZEND_USER_FUNCTION & & fn - > op_array . static_variables ) {
2014-09-19 06:01:05 +08:00
ce - > ce_flags | = ZEND_HAS_STATIC_IN_METHODS ;
}
}
}
/* }}} */
2014-12-14 06:06:14 +08:00
static int zend_traits_copy_functions ( zend_string * fnname , zend_function * fn , zend_class_entry * ce , HashTable * * overriden , HashTable * exclude_table ) /* { { { */
2014-09-19 06:01:05 +08:00
{
zend_trait_alias * alias , * * alias_ptr ;
zend_string * lcname ;
zend_function fn_copy ;
/* apply aliases which are qualified with a class name, there should not be any ambiguity */
if ( ce - > trait_aliases ) {
alias_ptr = ce - > trait_aliases ;
alias = * alias_ptr ;
while ( alias ) {
/* Scope unset or equal to the function we compare to, and the alias applies to fn */
if ( alias - > alias ! = NULL
& & ( ! alias - > trait_method - > ce | | fn - > common . scope = = alias - > trait_method - > ce )
2015-06-30 18:59:27 +08:00
& & ZSTR_LEN ( alias - > trait_method - > method_name ) = = ZSTR_LEN ( fnname )
& & ( zend_binary_strcasecmp ( ZSTR_VAL ( alias - > trait_method - > method_name ) , ZSTR_LEN ( alias - > trait_method - > method_name ) , ZSTR_VAL ( fnname ) , ZSTR_LEN ( fnname ) ) = = 0 ) ) {
2014-09-19 06:01:05 +08:00
fn_copy = * fn ;
/* if it is 0, no modifieres has been changed */
if ( alias - > modifiers ) {
fn_copy . common . fn_flags = alias - > modifiers | ( fn - > common . fn_flags ^ ( fn - > common . fn_flags & ZEND_ACC_PPP_MASK ) ) ;
}
2014-12-24 20:04:51 +08:00
lcname = zend_string_tolower ( alias - > alias ) ;
2015-06-30 18:59:27 +08:00
zend_add_trait_method ( ce , ZSTR_VAL ( alias - > alias ) , lcname , & fn_copy , overriden ) ;
2014-09-19 06:01:05 +08:00
zend_string_release ( lcname ) ;
/* Record the trait from which this alias was resolved. */
if ( ! alias - > trait_method - > ce ) {
alias - > trait_method - > ce = fn - > common . scope ;
}
}
alias_ptr + + ;
alias = * alias_ptr ;
}
}
if ( exclude_table = = NULL | | zend_hash_find ( exclude_table , fnname ) = = NULL ) {
/* is not in hashtable, thus, function is not to be excluded */
2015-07-10 22:26:53 +08:00
/* And how about ZEND_OVERLOADED_FUNCTION? */
memcpy ( & fn_copy , fn , fn - > type = = ZEND_USER_FUNCTION ? sizeof ( zend_op_array ) : sizeof ( zend_internal_function ) ) ;
2014-09-19 06:01:05 +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 ) {
/* Scope unset or equal to the function we compare to, and the alias applies to fn */
if ( alias - > alias = = NULL & & alias - > modifiers ! = 0
& & ( ! alias - > trait_method - > ce | | fn - > common . scope = = alias - > trait_method - > ce )
2015-06-30 18:59:27 +08:00
& & ( ZSTR_LEN ( alias - > trait_method - > method_name ) = = ZSTR_LEN ( fnname ) )
& & ( zend_binary_strcasecmp ( ZSTR_VAL ( alias - > trait_method - > method_name ) , ZSTR_LEN ( alias - > trait_method - > method_name ) , ZSTR_VAL ( fnname ) , ZSTR_LEN ( fnname ) ) = = 0 ) ) {
2014-09-19 06:01:05 +08:00
fn_copy . common . fn_flags = alias - > modifiers | ( fn - > common . fn_flags ^ ( fn - > common . fn_flags & ZEND_ACC_PPP_MASK ) ) ;
/** Record the trait from which this alias was resolved. */
if ( ! alias - > trait_method - > ce ) {
alias - > trait_method - > ce = fn - > common . scope ;
}
}
alias_ptr + + ;
alias = * alias_ptr ;
}
}
2015-06-30 18:59:27 +08:00
zend_add_trait_method ( ce , ZSTR_VAL ( fn - > common . function_name ) , fnname , & fn_copy , overriden ) ;
2014-09-19 06:01:05 +08:00
}
return ZEND_HASH_APPLY_KEEP ;
}
/* }}} */
2014-12-14 06:06:14 +08:00
static void zend_check_trait_usage ( zend_class_entry * ce , zend_class_entry * trait ) /* { { { */
2014-09-19 06:01:05 +08:00
{
uint32_t i ;
2015-03-05 07:10:38 +08:00
if ( UNEXPECTED ( ( trait - > ce_flags & ZEND_ACC_TRAIT ) ! = ZEND_ACC_TRAIT ) ) {
2015-06-30 18:59:27 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Class %s is not a trait, Only traits may be used in 'as' and 'insteadof' statements " , ZSTR_VAL ( trait - > name ) ) ;
2014-09-19 06:01:05 +08:00
}
for ( i = 0 ; i < ce - > num_traits ; i + + ) {
if ( ce - > traits [ i ] = = trait ) {
return ;
}
}
2015-06-30 18:59:27 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Required Trait %s wasn't added to %s " , ZSTR_VAL ( trait - > name ) , ZSTR_VAL ( ce - > name ) ) ;
2014-09-19 06:01:05 +08:00
}
/* }}} */
2014-12-14 06:06:14 +08:00
static void zend_traits_init_trait_structures ( zend_class_entry * ce ) /* { { { */
2014-09-19 06:01:05 +08:00
{
size_t i , j = 0 ;
2015-03-05 21:06:59 +08:00
zend_trait_precedence * * precedences ;
2014-09-19 06:01:05 +08:00
zend_trait_precedence * cur_precedence ;
zend_trait_method_reference * cur_method_ref ;
zend_string * lcname ;
zend_bool method_exists ;
/* resolve class references */
if ( ce - > trait_precedences ) {
i = 0 ;
2015-03-05 21:06:59 +08:00
precedences = ce - > trait_precedences ;
ce - > trait_precedences = NULL ;
while ( ( cur_precedence = precedences [ i ] ) ) {
2014-09-19 06:01:05 +08:00
/** Resolve classes for all precedence operations. */
if ( cur_precedence - > exclude_from_classes ) {
cur_method_ref = cur_precedence - > trait_method ;
if ( ! ( cur_precedence - > trait_method - > ce = zend_fetch_class ( cur_method_ref - > class_name ,
2014-12-14 06:06:14 +08:00
ZEND_FETCH_CLASS_TRAIT | ZEND_FETCH_CLASS_NO_AUTOLOAD ) ) ) {
2015-06-30 18:59:27 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Could not find trait %s " , ZSTR_VAL ( cur_method_ref - > class_name ) ) ;
2014-09-19 06:01:05 +08:00
}
2014-12-14 06:06:14 +08:00
zend_check_trait_usage ( ce , cur_precedence - > trait_method - > ce ) ;
2014-09-19 06:01:05 +08:00
2014-11-20 03:59:31 +08:00
/** Ensure that the preferred method is actually available. */
2014-12-24 20:04:51 +08:00
lcname = zend_string_tolower ( cur_method_ref - > method_name ) ;
2014-09-19 06:01:05 +08:00
method_exists = zend_hash_exists ( & cur_method_ref - > ce - > function_table ,
lcname ) ;
2014-12-24 20:04:51 +08:00
zend_string_release ( lcname ) ;
2014-09-19 06:01:05 +08:00
if ( ! method_exists ) {
zend_error_noreturn ( E_COMPILE_ERROR ,
" A precedence rule was defined for %s::%s but this method does not exist " ,
2015-06-30 18:59:27 +08:00
ZSTR_VAL ( cur_method_ref - > ce - > name ) ,
ZSTR_VAL ( cur_method_ref - > method_name ) ) ;
2014-09-19 06:01:05 +08:00
}
/** With the other traits, we are more permissive.
We do not give errors for those . This allows to be more
defensive in such definitions .
However , we want to make sure that the insteadof declaration
is consistent in itself .
*/
j = 0 ;
while ( cur_precedence - > exclude_from_classes [ j ] . class_name ) {
zend_string * class_name = cur_precedence - > exclude_from_classes [ j ] . class_name ;
2015-03-05 21:06:59 +08:00
if ( ! ( cur_precedence - > exclude_from_classes [ j ] . ce = zend_fetch_class ( class_name , ZEND_FETCH_CLASS_TRAIT | ZEND_FETCH_CLASS_NO_AUTOLOAD ) ) ) {
2015-06-30 18:59:27 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Could not find trait %s " , ZSTR_VAL ( class_name ) ) ;
2014-09-19 06:01:05 +08:00
}
2015-03-05 21:06:59 +08:00
zend_check_trait_usage ( ce , cur_precedence - > exclude_from_classes [ j ] . ce ) ;
2014-09-19 06:01:05 +08:00
/* make sure that the trait method is not from a class mentioned in
exclude_from_classes , for consistency */
2015-03-05 21:06:59 +08:00
if ( cur_precedence - > trait_method - > ce = = cur_precedence - > exclude_from_classes [ j ] . ce ) {
2014-09-19 06:01:05 +08:00
zend_error_noreturn ( E_COMPILE_ERROR ,
" Inconsistent insteadof definition. "
" The method %s is to be used from %s, but %s is also on the exclude list " ,
2015-06-30 18:59:27 +08:00
ZSTR_VAL ( cur_method_ref - > method_name ) ,
ZSTR_VAL ( cur_precedence - > trait_method - > ce - > name ) ,
ZSTR_VAL ( cur_precedence - > trait_method - > ce - > name ) ) ;
2014-09-19 06:01:05 +08:00
}
zend_string_release ( class_name ) ;
j + + ;
}
}
i + + ;
}
2015-03-05 21:06:59 +08:00
ce - > trait_precedences = precedences ;
2014-09-19 06:01:05 +08:00
}
if ( ce - > trait_aliases ) {
i = 0 ;
while ( ce - > trait_aliases [ i ] ) {
/** For all aliases with an explicit class name, resolve the class now. */
if ( ce - > trait_aliases [ i ] - > trait_method - > class_name ) {
cur_method_ref = ce - > trait_aliases [ i ] - > trait_method ;
2014-12-14 06:06:14 +08:00
if ( ! ( cur_method_ref - > ce = zend_fetch_class ( cur_method_ref - > class_name , ZEND_FETCH_CLASS_TRAIT | ZEND_FETCH_CLASS_NO_AUTOLOAD ) ) ) {
2015-06-30 18:59:27 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " Could not find trait %s " , ZSTR_VAL ( cur_method_ref - > class_name ) ) ;
2014-09-19 06:01:05 +08:00
}
2014-12-14 06:06:14 +08:00
zend_check_trait_usage ( ce , cur_method_ref - > ce ) ;
2014-09-19 06:01:05 +08:00
/** And, ensure that the referenced method is resolvable, too. */
2014-12-24 20:04:51 +08:00
lcname = zend_string_tolower ( cur_method_ref - > method_name ) ;
2014-09-19 06:01:05 +08:00
method_exists = zend_hash_exists ( & cur_method_ref - > ce - > function_table ,
lcname ) ;
2014-12-24 20:04:51 +08:00
zend_string_release ( lcname ) ;
2014-09-19 06:01:05 +08:00
if ( ! method_exists ) {
2015-06-30 18:59:27 +08:00
zend_error_noreturn ( E_COMPILE_ERROR , " An alias was defined for %s::%s but this method does not exist " , ZSTR_VAL ( cur_method_ref - > ce - > name ) , ZSTR_VAL ( cur_method_ref - > method_name ) ) ;
2014-09-19 06:01:05 +08:00
}
}
i + + ;
}
}
}
/* }}} */
static void zend_traits_compile_exclude_table ( HashTable * exclude_table , zend_trait_precedence * * precedences , zend_class_entry * trait ) /* { { { */
{
size_t i = 0 , j ;
if ( ! precedences ) {
return ;
}
while ( precedences [ i ] ) {
if ( precedences [ i ] - > exclude_from_classes ) {
j = 0 ;
while ( precedences [ i ] - > exclude_from_classes [ j ] . ce ) {
if ( precedences [ i ] - > exclude_from_classes [ j ] . ce = = trait ) {
2015-01-03 17:22:58 +08:00
zend_string * lcname =
2014-12-24 20:04:51 +08:00
zend_string_tolower ( precedences [ i ] - > trait_method - > method_name ) ;
2014-09-19 06:01:05 +08:00
if ( zend_hash_add_empty_element ( exclude_table , lcname ) = = NULL ) {
zend_string_release ( lcname ) ;
2015-06-30 18:59:27 +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 " , ZSTR_VAL ( precedences [ i ] - > trait_method - > method_name ) , ZSTR_VAL ( trait - > name ) ) ;
2014-09-19 06:01:05 +08:00
}
zend_string_release ( lcname ) ;
}
+ + j ;
}
}
+ + i ;
}
}
/* }}} */
2014-12-14 06:06:14 +08:00
static void zend_do_traits_method_binding ( zend_class_entry * ce ) /* { { { */
2014-09-19 06:01:05 +08:00
{
uint32_t i ;
HashTable * overriden = NULL ;
zend_string * key ;
zend_function * fn ;
for ( i = 0 ; i < ce - > num_traits ; i + + ) {
if ( ce - > trait_precedences ) {
HashTable exclude_table ;
2015-03-05 18:41:12 +08:00
zend_trait_precedence * * precedences ;
2014-09-19 06:01:05 +08:00
/* TODO: revisit this start size, may be its not optimal */
zend_hash_init_ex ( & exclude_table , 8 , NULL , NULL , 0 , 0 ) ;
2015-03-05 18:41:12 +08:00
precedences = ce - > trait_precedences ;
ce - > trait_precedences = NULL ;
zend_traits_compile_exclude_table ( & exclude_table , precedences , ce - > traits [ i ] ) ;
2014-09-19 06:01:05 +08:00
/* copies functions, applies defined aliasing, and excludes unused trait methods */
ZEND_HASH_FOREACH_STR_KEY_PTR ( & ce - > traits [ i ] - > function_table , key , fn ) {
2014-12-14 06:06:14 +08:00
zend_traits_copy_functions ( key , fn , ce , & overriden , & exclude_table ) ;
2014-09-19 06:01:05 +08:00
} ZEND_HASH_FOREACH_END ( ) ;
zend_hash_destroy ( & exclude_table ) ;
2015-03-05 18:41:12 +08:00
ce - > trait_precedences = precedences ;
2014-09-19 06:01:05 +08:00
} else {
ZEND_HASH_FOREACH_STR_KEY_PTR ( & ce - > traits [ i ] - > function_table , key , fn ) {
2014-12-14 06:06:14 +08:00
zend_traits_copy_functions ( key , fn , ce , & overriden , NULL ) ;
2014-09-19 06:01:05 +08:00
} ZEND_HASH_FOREACH_END ( ) ;
}
}
ZEND_HASH_FOREACH_PTR ( & ce - > function_table , fn ) {
zend_fixup_trait_method ( fn , ce ) ;
} ZEND_HASH_FOREACH_END ( ) ;
2015-03-05 18:41:12 +08:00
if ( ce - > trait_precedences ) {
i = 0 ;
while ( ce - > trait_precedences [ i ] ) {
if ( ce - > trait_precedences [ i ] - > exclude_from_classes ) {
efree ( ce - > trait_precedences [ i ] - > exclude_from_classes ) ;
ce - > trait_precedences [ i ] - > exclude_from_classes = NULL ;
}
i + + ;
}
}
2014-09-19 06:01:05 +08:00
if ( overriden ) {
zend_hash_destroy ( overriden ) ;
FREE_HASHTABLE ( overriden ) ;
}
}
/* }}} */
static zend_class_entry * find_first_definition ( zend_class_entry * ce , size_t current_trait , zend_string * prop_name , zend_class_entry * coliding_ce ) /* { { { */
{
size_t i ;
if ( coliding_ce = = ce ) {
for ( i = 0 ; i < current_trait ; i + + ) {
if ( zend_hash_exists ( & ce - > traits [ i ] - > properties_info , prop_name ) ) {
return ce - > traits [ i ] ;
}
}
}
return coliding_ce ;
}
/* }}} */
2014-12-14 06:06:14 +08:00
static void zend_do_traits_property_binding ( zend_class_entry * ce ) /* { { { */
2014-09-19 06:01:05 +08:00
{
size_t i ;
zend_property_info * property_info ;
zend_property_info * coliding_prop ;
zend_string * prop_name ;
const char * class_name_unused ;
zend_bool not_compatible ;
zval * prop_value ;
uint32_t flags ;
zend_string * doc_comment ;
/* 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
*/
for ( i = 0 ; i < ce - > num_traits ; i + + ) {
ZEND_HASH_FOREACH_PTR ( & ce - > traits [ i ] - > properties_info , property_info ) {
/* first get the unmangeld name if necessary,
* then check whether the property is already there
*/
flags = property_info - > flags ;
2015-06-03 18:43:05 +08:00
if ( flags & ZEND_ACC_PUBLIC ) {
2014-09-19 06:01:05 +08:00
prop_name = zend_string_copy ( property_info - > name ) ;
} else {
const char * pname ;
size_t pname_len ;
/* for private and protected we need to unmangle the names */
zend_unmangle_property_name_ex ( property_info - > name ,
& class_name_unused , & pname , & pname_len ) ;
prop_name = zend_string_init ( pname , pname_len , 0 ) ;
}
/* next: check for conflicts with current class */
if ( ( coliding_prop = zend_hash_find_ptr ( & ce - > properties_info , prop_name ) ) ! = NULL ) {
if ( coliding_prop - > flags & ZEND_ACC_SHADOW ) {
2015-03-04 22:41:01 +08:00
zend_string_release ( coliding_prop - > name ) ;
if ( coliding_prop - > doc_comment ) {
zend_string_release ( coliding_prop - > doc_comment ) ;
}
2014-09-19 06:01:05 +08:00
zend_hash_del ( & ce - > properties_info , prop_name ) ;
flags | = ZEND_ACC_CHANGED ;
} else {
2017-09-27 08:31:03 +08:00
not_compatible = 1 ;
2014-09-19 06:01:05 +08:00
if ( ( coliding_prop - > flags & ( ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC ) )
= = ( flags & ( ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC ) ) ) {
2017-09-27 08:31:03 +08:00
/* the flags are identical, thus, the properties may be compatible */
zval op1 , op2 ;
2014-09-19 06:01:05 +08:00
if ( flags & ZEND_ACC_STATIC ) {
2017-09-27 08:31:03 +08:00
ZVAL_COPY_OR_DUP ( & op1 , & ce - > default_static_members_table [ coliding_prop - > offset ] ) ;
ZVAL_COPY_OR_DUP ( & op2 , & ce - > traits [ i ] - > default_static_members_table [ property_info - > offset ] ) ;
2014-09-19 06:01:05 +08:00
} else {
2017-09-27 08:31:03 +08:00
ZVAL_COPY_OR_DUP ( & op1 , & ce - > default_properties_table [ OBJ_PROP_TO_NUM ( coliding_prop - > offset ) ] ) ;
ZVAL_COPY_OR_DUP ( & op2 , & ce - > traits [ i ] - > default_properties_table [ OBJ_PROP_TO_NUM ( property_info - > offset ) ] ) ;
}
/* if any of the values is a constant, we try to resolve it */
if ( UNEXPECTED ( Z_TYPE ( op1 ) = = IS_CONSTANT_AST ) ) {
zval_update_constant_ex ( & op1 , ce ) ;
2014-09-19 06:01:05 +08:00
}
2017-09-27 08:31:03 +08:00
if ( UNEXPECTED ( Z_TYPE ( op2 ) = = IS_CONSTANT_AST ) ) {
zval_update_constant_ex ( & op2 , ce ) ;
}
not_compatible = fast_is_not_identical_function ( & op1 , & op2 ) ;
zval_ptr_dtor_nogc ( & op1 ) ;
zval_ptr_dtor_nogc ( & op2 ) ;
2014-09-19 06:01:05 +08:00
}
if ( not_compatible ) {
zend_error_noreturn ( E_COMPILE_ERROR ,
" %s and %s define the same property ($%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed " ,
2015-06-30 18:59:27 +08:00
ZSTR_VAL ( find_first_definition ( ce , i , prop_name , coliding_prop - > ce ) - > name ) ,
ZSTR_VAL ( property_info - > ce - > name ) ,
ZSTR_VAL ( prop_name ) ,
ZSTR_VAL ( ce - > name ) ) ;
2014-09-19 06:01:05 +08:00
}
2015-03-15 16:47:25 +08:00
zend_string_release ( prop_name ) ;
continue ;
2014-09-19 06:01:05 +08:00
}
}
/* property not found, so lets add it */
if ( flags & ZEND_ACC_STATIC ) {
prop_value = & ce - > traits [ i ] - > default_static_members_table [ property_info - > offset ] ;
} else {
2014-11-06 19:50:03 +08:00
prop_value = & ce - > traits [ i ] - > default_properties_table [ OBJ_PROP_TO_NUM ( property_info - > offset ) ] ;
2014-09-19 06:01:05 +08:00
}
2017-11-01 10:25:10 +08:00
Z_TRY_ADDREF_P ( prop_value ) ;
2014-09-19 06:01:05 +08:00
doc_comment = property_info - > doc_comment ? zend_string_copy ( property_info - > doc_comment ) : NULL ;
zend_declare_property_ex ( ce , prop_name ,
prop_value , flags ,
2014-12-14 06:06:14 +08:00
doc_comment ) ;
2014-09-19 06:01:05 +08:00
zend_string_release ( prop_name ) ;
} ZEND_HASH_FOREACH_END ( ) ;
}
}
/* }}} */
2014-12-14 06:06:14 +08:00
static void zend_do_check_for_inconsistent_traits_aliasing ( zend_class_entry * ce ) /* { { { */
2014-09-19 06:01:05 +08:00
{
int i = 0 ;
zend_trait_alias * cur_alias ;
zend_string * lc_method_name ;
if ( ce - > trait_aliases ) {
while ( ce - > trait_aliases [ i ] ) {
cur_alias = ce - > trait_aliases [ i ] ;
/** The trait for this alias has not been resolved, this means, this
alias was not applied . Abort with an error . */
if ( ! cur_alias - > trait_method - > ce ) {
if ( cur_alias - > alias ) {
/** Plain old inconsistency/typo/bug */
zend_error_noreturn ( E_COMPILE_ERROR ,
" An alias (%s) was defined for method %s(), but this method does not exist " ,
2015-06-30 18:59:27 +08:00
ZSTR_VAL ( cur_alias - > alias ) ,
ZSTR_VAL ( cur_alias - > trait_method - > method_name ) ) ;
2014-09-19 06:01:05 +08:00
} else {
/** 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 . */
2014-12-24 20:04:51 +08:00
lc_method_name = zend_string_tolower (
cur_alias - > trait_method - > method_name ) ;
2014-09-19 06:01:05 +08:00
if ( zend_hash_exists ( & ce - > function_table ,
lc_method_name ) ) {
2014-12-24 20:04:51 +08:00
zend_string_release ( lc_method_name ) ;
2014-09-19 06:01:05 +08:00
zend_error_noreturn ( E_COMPILE_ERROR ,
2014-11-20 03:59:31 +08:00
" The modifiers for the trait alias %s() need to be changed in the same statement in which the alias is defined. Error " ,
2015-06-30 18:59:27 +08:00
ZSTR_VAL ( cur_alias - > trait_method - > method_name ) ) ;
2014-09-19 06:01:05 +08:00
} else {
2014-12-24 20:04:51 +08:00
zend_string_release ( lc_method_name ) ;
2014-09-19 06:01:05 +08:00
zend_error_noreturn ( E_COMPILE_ERROR ,
" The modifiers of the trait method %s() are changed, but this method does not exist. Error " ,
2015-06-30 18:59:27 +08:00
ZSTR_VAL ( cur_alias - > trait_method - > method_name ) ) ;
2014-09-19 06:01:05 +08:00
}
}
}
i + + ;
}
}
}
/* }}} */
2014-12-14 06:06:14 +08:00
ZEND_API void zend_do_bind_traits ( zend_class_entry * ce ) /* { { { */
2014-09-19 06:01:05 +08:00
{
2017-11-18 04:35:22 +08:00
if ( ce - > num_traits = = 0 ) {
2014-09-19 06:01:05 +08:00
return ;
}
/* complete initialization of trait strutures in ce */
2014-12-14 06:06:14 +08:00
zend_traits_init_trait_structures ( ce ) ;
2014-09-19 06:01:05 +08:00
/* first care about all methods to be flattened into the class */
2014-12-14 06:06:14 +08:00
zend_do_traits_method_binding ( ce ) ;
2014-09-19 06:01:05 +08:00
/* Aliases which have not been applied indicate typos/bugs. */
2014-12-14 06:06:14 +08:00
zend_do_check_for_inconsistent_traits_aliasing ( ce ) ;
2014-09-19 06:01:05 +08:00
/* then flatten the properties into it, to, mostly to notfiy developer about problems */
2014-12-14 06:06:14 +08:00
zend_do_traits_property_binding ( ce ) ;
2014-09-19 06:01:05 +08:00
/* verify that all abstract methods from traits have been implemented */
2014-12-14 06:06:14 +08:00
zend_verify_abstract_class ( ce ) ;
2014-09-19 06:01:05 +08:00
2015-03-31 22:10:22 +08:00
/* Emit E_DEPRECATED for PHP 4 constructors */
zend_check_deprecated_constructor ( ce ) ;
2014-09-19 06:01:05 +08:00
/* now everything should be fine and an added ZEND_ACC_IMPLICIT_ABSTRACT_CLASS should be removed */
if ( ce - > ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS ) {
ce - > ce_flags - = ZEND_ACC_IMPLICIT_ABSTRACT_CLASS ;
}
}
/* }}} */
2015-03-31 22:10:22 +08:00
static zend_bool zend_has_deprecated_constructor ( const zend_class_entry * ce ) /* { { { */
{
const zend_string * constructor_name ;
if ( ! ce - > constructor ) {
return 0 ;
}
constructor_name = ce - > constructor - > common . function_name ;
return ! zend_binary_strcasecmp (
2015-06-30 18:59:27 +08:00
ZSTR_VAL ( ce - > name ) , ZSTR_LEN ( ce - > name ) ,
ZSTR_VAL ( constructor_name ) , ZSTR_LEN ( constructor_name )
2015-03-31 22:10:22 +08:00
) ;
}
/* }}} */
void zend_check_deprecated_constructor ( const zend_class_entry * ce ) /* { { { */
{
if ( zend_has_deprecated_constructor ( ce ) ) {
2015-06-30 18:59:27 +08:00
zend_error ( E_DEPRECATED , " Methods with the same name as their class will not be constructors in a future version of PHP; %s has a deprecated constructor " , ZSTR_VAL ( ce - > name ) ) ;
2015-03-31 22:10:22 +08:00
}
}
/* }}} */
2014-09-20 15:12:08 +08:00
/*
* Local variables :
* tab - width : 4
* c - basic - offset : 4
* indent - tabs - mode : t
* End :
2017-07-05 00:12:45 +08:00
* vim600 : sw = 4 ts = 4 fdm = marker
* vim < 600 : sw = 4 ts = 4
2014-09-20 15:12:08 +08:00
*/