📄 aggregation.c
字号:
/* +----------------------------------------------------------------------+ | PHP Version 4 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2007 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Andrei Zmievski <andrei@php.net> | +----------------------------------------------------------------------+*//* $Id: aggregation.c,v 1.11.4.7.4.3 2007/01/01 09:46:47 sebastian Exp $ */#include "php.h"#include "basic_functions.h"#include "aggregation.h"#if (HAVE_PCRE || HAVE_BUNDLED_PCRE) && !defined(COMPILE_DL_PCRE)#include "ext/pcre/php_pcre.h"#endifstatic void aggregation_info_dtor(aggregation_info *info){#ifndef ZEND_ENGINE_2 destroy_zend_class(info->new_ce); efree(info->new_ce);#else destroy_zend_class(&info->new_ce);#endif zval_ptr_dtor(&info->aggr_members);}/* {{{ static zval* array_to_hash */static zval *array_to_hash(zval *array){ zval *hash, **entry; char *name_lc; /* * Well, this just transposes the array, popularly known as flipping it, or * giving it the finger. */ MAKE_STD_ZVAL(hash); array_init(hash); for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(array)); zend_hash_get_current_data(Z_ARRVAL_P(array), (void**)&entry) == SUCCESS; zend_hash_move_forward(Z_ARRVAL_P(array))) { if (Z_TYPE_PP(entry) == IS_STRING) { /* * I hate case-insensitivity. Die, die, die. */ name_lc = estrndup(Z_STRVAL_PP(entry), Z_STRLEN_PP(entry)); zend_str_tolower(name_lc, Z_STRLEN_PP(entry)); add_assoc_bool_ex(hash, name_lc, Z_STRLEN_PP(entry)+1, 1); efree(name_lc); } } return hash;}/* }}} *//* {{{ static void aggregate_methods() */static void aggregate_methods(zend_class_entry *ce, zend_class_entry *from_ce, int aggr_type, zval *aggr_filter, zend_bool exclude, zval *aggr_methods TSRMLS_DC){ HashPosition pos; zend_function *function; char *func_name; uint func_name_len; ulong num_key; zval *list_hash = NULL;#if (HAVE_PCRE || HAVE_BUNDLED_PCRE) && !defined(COMPILE_DL_PCRE) pcre *re = NULL; pcre_extra *re_extra = NULL; int re_options = 0;#endif /* * Flip the array for easy lookup, or compile the regexp. */ if (aggr_type == AGGREGATE_BY_LIST) { list_hash = array_to_hash(aggr_filter); }#if (HAVE_PCRE || HAVE_BUNDLED_PCRE) && !defined(COMPILE_DL_PCRE) else if (aggr_type == AGGREGATE_BY_REGEXP) { if ((re = pcre_get_compiled_regex(Z_STRVAL_P(aggr_filter), &re_extra, &re_options)) == NULL) { return; } }#endif /* * "Just because it's not nice doesn't mean it's not miraculous." * -- _Interesting Times_, Terry Pratchett */ /* * Aggregating by list without exclusion can be done more efficiently if we * iterate through the list and check against function table instead of the * other way around. */ if (aggr_type != AGGREGATE_BY_LIST || exclude) { zend_hash_internal_pointer_reset_ex(&from_ce->function_table, &pos); while (zend_hash_get_current_data_ex(&from_ce->function_table, (void**)&function, &pos) == SUCCESS) { zend_hash_get_current_key_ex(&from_ce->function_table, &func_name, &func_name_len, &num_key, 0, &pos); /* We do not aggregate: * 1. constructors */ if (!strncmp(func_name, from_ce->name, MAX(func_name_len-1, from_ce->name_length)) || /* 2. private methods (heh, like we really have them) */ func_name[0] == '_' || /* 3. explicitly excluded methods */ (aggr_type == AGGREGATE_BY_LIST && zend_hash_exists(Z_ARRVAL_P(list_hash), func_name, func_name_len))#if (HAVE_PCRE || HAVE_BUNDLED_PCRE) && !defined(COMPILE_DL_PCRE) || /* 4. methods matching regexp as modified by the exclusion flag */ (aggr_type == AGGREGATE_BY_REGEXP && (pcre_exec(re, re_extra, func_name, func_name_len-1, 0, 0, NULL, 0) < 0) ^ exclude) == 1#endif ) { zend_hash_move_forward_ex(&from_ce->function_table, &pos); continue; } /* * This is where the magic happens. */ if (zend_hash_add(&ce->function_table, func_name, func_name_len, (void*)function, sizeof(zend_function), NULL) == SUCCESS) { function_add_ref(function); add_next_index_stringl(aggr_methods, func_name, func_name_len-1, 1); } zend_hash_move_forward_ex(&from_ce->function_table, &pos); } } else { /* * This is just like above except the other way around. */ zend_hash_internal_pointer_reset(Z_ARRVAL_P(list_hash)); while (zend_hash_get_current_key_ex(Z_ARRVAL_P(list_hash), &func_name, &func_name_len, &num_key, 0, NULL) == HASH_KEY_IS_STRING) { if (!strncmp(func_name, from_ce->name, MAX(func_name_len-1, from_ce->name_length)) || func_name[0] == '_' || zend_hash_find(&from_ce->function_table, func_name, func_name_len, (void**)&function) == FAILURE) { zend_hash_move_forward(Z_ARRVAL_P(list_hash)); continue; } if (zend_hash_add(&ce->function_table, func_name, func_name_len, (void*)function, sizeof(zend_function), NULL) == SUCCESS) { function_add_ref(function); add_next_index_stringl(aggr_methods, func_name, func_name_len-1, 1); } zend_hash_move_forward(Z_ARRVAL_P(list_hash)); } } if (list_hash) { zval_ptr_dtor(&list_hash); }}/* }}} *//* {{{ static void aggregate_properties() */static void aggregate_properties(zval *obj, zend_class_entry *from_ce, int aggr_type, zval *aggr_filter, zend_bool exclude, zval *aggr_props TSRMLS_DC){ HashPosition pos; zval **prop; char *prop_name; uint prop_name_len; ulong num_key; zval *list_hash = NULL;#if (HAVE_PCRE || HAVE_BUNDLED_PCRE) && !defined(COMPILE_DL_PCRE) pcre *re = NULL; pcre_extra *re_extra = NULL; int re_options = 0;#endif if (!from_ce->constants_updated) { zend_hash_apply_with_argument(&from_ce->default_properties, (apply_func_arg_t) zval_update_constant, (void *) 1 TSRMLS_CC); from_ce->constants_updated = 1; } /* * Flip the array for easy lookup, or compile the regexp. */ if (aggr_type == AGGREGATE_BY_LIST) { list_hash = array_to_hash(aggr_filter); }#if (HAVE_PCRE || HAVE_BUNDLED_PCRE) && !defined(COMPILE_DL_PCRE) else if (aggr_type == AGGREGATE_BY_REGEXP) { if ((re = pcre_get_compiled_regex(Z_STRVAL_P(aggr_filter), &re_extra, &re_options)) == NULL) { return; } }#endif /* * "Just because it's not nice doesn't mean it's not miraculous." * -- _Interesting Times_, Terry Pratchett */ /* * Aggregating by list without exclusion can be done more efficiently if we * iterate through the list and check against default properties table * instead of the other way around. */ if (aggr_type != AGGREGATE_BY_LIST || exclude) { zend_hash_internal_pointer_reset_ex(&from_ce->default_properties, &pos); while (zend_hash_get_current_data_ex(&from_ce->default_properties, (void**)&prop, &pos) == SUCCESS) { zend_hash_get_current_key_ex(&from_ce->default_properties, &prop_name, &prop_name_len, &num_key, 0, &pos); /* We do not aggregate: * 1. private properties (heh, like we really have them) */ if (prop_name[0] == '_' || /* 2. explicitly excluded properties */ (aggr_type == AGGREGATE_BY_LIST && zend_hash_exists(Z_ARRVAL_P(list_hash), prop_name, prop_name_len))#if (HAVE_PCRE || HAVE_BUNDLED_PCRE) && !defined(COMPILE_DL_PCRE) || /* 3. properties matching regexp as modified by the exclusion flag */ (aggr_type == AGGREGATE_BY_REGEXP && (pcre_exec(re, re_extra, prop_name, prop_name_len-1, 0, 0, NULL, 0) < 0) ^ exclude) == 1#endif ) { zend_hash_move_forward_ex(&from_ce->default_properties, &pos); continue; } /* * This is where the magic happens. */ if (zend_hash_add(Z_OBJPROP_P(obj), prop_name, prop_name_len, (void*)prop, sizeof(zval *), NULL) == SUCCESS) { zval_add_ref(prop); add_next_index_stringl(aggr_props, prop_name, prop_name_len-1, 1); } zend_hash_move_forward_ex(&from_ce->default_properties, &pos); } } else { /* * This is just like above except the other way around. */ zend_hash_internal_pointer_reset(Z_ARRVAL_P(list_hash)); while (zend_hash_get_current_key_ex(Z_ARRVAL_P(list_hash), &prop_name, &prop_name_len, &num_key, 0, NULL) == HASH_KEY_IS_STRING) { if (prop_name[0] == '_' || zend_hash_find(&from_ce->default_properties, prop_name, prop_name_len, (void**)&prop) == FAILURE) { zend_hash_move_forward(Z_ARRVAL_P(list_hash)); continue; } if (zend_hash_add(Z_OBJPROP_P(obj), prop_name, prop_name_len, (void*)prop, sizeof(zval *), NULL) == SUCCESS) { zval_add_ref(prop); add_next_index_stringl(aggr_props, prop_name, prop_name_len-1, 1); } zend_hash_move_forward(Z_ARRVAL_P(list_hash)); } } if (list_hash) { zval_ptr_dtor(&list_hash); }}/* }}} *//* {{{ static void aggregate() */static void aggregate(INTERNAL_FUNCTION_PARAMETERS, int aggr_what, int aggr_type){ /* Incoming parameters. */ zval *obj, *aggr_list = NULL; char *class_name, *class_name_lc, *aggr_regexp; int class_name_len, aggr_regexp_len; zend_bool exclude = 0; /* Other variables. */ zval **aggr_members, z_aggr_regexp; zend_class_entry *ce, *new_ce; zend_function tmp_zend_function; aggregation_info aggr_info_new, *aggr_info = &aggr_info_new; zval *aggr_methods_new, **aggr_methods = &aggr_methods_new; zval *aggr_props_new, **aggr_props = &aggr_props_new; zval *aggr_filter = NULL; int zpp_result = FAILURE; /* * Ah, the beauty of the new parameter parsing API. Almost as good as Heidi Klum. */ switch (aggr_type) { case AGGREGATE_ALL: zpp_result = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "os", &obj, &class_name, &class_name_len); break; case AGGREGATE_BY_LIST: zpp_result = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "osa|b", &obj, &class_name, &class_name_len, &aggr_list, &exclude); break; case AGGREGATE_BY_REGEXP: zpp_result = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "oss|b", &obj, &class_name, &class_name_len, &aggr_regexp, &aggr_regexp_len, &exclude); ZVAL_STRINGL(&z_aggr_regexp, aggr_regexp, aggr_regexp_len, 0); break; } if (zpp_result == FAILURE) { return; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -