PHP Classes

File: ext/kernel/object.c

Recommend this page to a friend!
  Classes of Andrew Collington   iWire PHP Raspberry PI GPIO Class   ext/kernel/object.c   Download  
File: ext/kernel/object.c
Role: Auxiliary data
Content type: text/plain
Description: Auxiliary data
Class: iWire PHP Raspberry PI GPIO Class
Control a Raspberry PI board using GPIO
Author: By
Last change:
Date: 5 years ago
Size: 49,155 bytes
 

Contents

Class file image Download
/* +------------------------------------------------------------------------+ | Zephir Language | +------------------------------------------------------------------------+ | Copyright (c) 2011-2015 Zephir Team (http://www.zephir-lang.com) | +------------------------------------------------------------------------+ | This source file is subject to the New BSD License that is bundled | | with this package in the file docs/LICENSE.txt. | | | | If you did not receive a copy of the license and are unable to | | obtain it through the world-wide-web, please send an email | | to license@zephir-lang.com so we can send you a copy immediately. | +------------------------------------------------------------------------+ | Authors: Andres Gutierrez <andres@zephir-lang.com> | | Eduar Carvajal <eduar@zephir-lang.com> | | Vladimir Kolesnikov <vladimir@extrememember.com> | +------------------------------------------------------------------------+ */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <php.h> #include "php_ext.h" #include <Zend/zend_closures.h> #include "kernel/main.h" #include "kernel/memory.h" #include "kernel/object.h" #include "kernel/exception.h" #include "kernel/fcall.h" #include "kernel/hash.h" #include "kernel/array.h" #include "kernel/operators.h" /** * Reads class constant from string name and returns its value */ int zephir_get_class_constant(zval *return_value, zend_class_entry *ce, char *constant_name, unsigned int constant_length TSRMLS_DC) { zval **result_ptr; if (zephir_hash_find(&ce->constants_table, constant_name, constant_length, (void **) &result_ptr) != SUCCESS) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "Undefined class constant '%s::%s'", ce->name, constant_name); return FAILURE; } ZVAL_ZVAL(return_value, *result_ptr, 1, 0); return SUCCESS; } /** * Check if class is instance of */ int zephir_instance_of(zval *result, const zval *object, const zend_class_entry *ce TSRMLS_DC) { if (Z_TYPE_P(object) != IS_OBJECT) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "instanceof expects an object instance"); ZVAL_FALSE(result); return FAILURE; } ZVAL_BOOL(result, instanceof_function(Z_OBJCE_P(object), ce TSRMLS_CC)); return SUCCESS; } int zephir_instance_of_ev(const zval *object, const zend_class_entry *ce TSRMLS_DC) { if (Z_TYPE_P(object) != IS_OBJECT) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "instanceof expects an object instance"); return 0; } return instanceof_function(Z_OBJCE_P(object), ce TSRMLS_CC); } /** * Check if an object is instance of a class */ int zephir_is_instance_of(zval *object, const char *class_name, unsigned int class_length TSRMLS_DC) { zend_class_entry *ce, *temp_ce; if (Z_TYPE_P(object) == IS_OBJECT) { ce = Z_OBJCE_P(object); if (ce->name_length == class_length) { if (!zend_binary_strcasecmp(ce->name, ce->name_length, class_name, class_length)) { return 1; } } temp_ce = zend_fetch_class(class_name, class_length, ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC); if (temp_ce) { return instanceof_function(ce, temp_ce TSRMLS_CC); } } return 0; } int zephir_zval_is_traversable(zval *object TSRMLS_DC) { zend_class_entry *ce; zend_uint i; if (Z_TYPE_P(object) == IS_OBJECT) { ce = Z_OBJCE_P(object); if (ce->get_iterator || (ce->parent && ce->parent->get_iterator)) { return 1; } for (i = 0; i < ce->num_interfaces; i++) { if (ce->interfaces[i] == zend_ce_aggregate || ce->interfaces[i] == zend_ce_iterator || ce->interfaces[i] == zend_ce_traversable ) { return 1; } } } return 0; } /** * Returns a class name into a zval result */ void zephir_get_class(zval *result, zval *object, int lower TSRMLS_DC) { zend_class_entry *ce; if (Z_TYPE_P(object) == IS_OBJECT) { ce = Z_OBJCE_P(object); Z_STRLEN_P(result) = ce->name_length; Z_STRVAL_P(result) = (char *) emalloc(ce->name_length + 1); memcpy(Z_STRVAL_P(result), ce->name, ce->name_length); Z_STRVAL_P(result)[Z_STRLEN_P(result)] = 0; Z_TYPE_P(result) = IS_STRING; if (lower) { zend_str_tolower(Z_STRVAL_P(result), Z_STRLEN_P(result)); } } else { ZVAL_NULL(result); php_error_docref(NULL TSRMLS_CC, E_WARNING, "zephir_get_class expects an object"); } } /** * Returns a class name into a zval result */ void zephir_get_class_ns(zval *result, zval *object, int lower TSRMLS_DC) { int found = 0; zend_class_entry *ce; unsigned int i, class_length; const char *cursor, *class_name; if (Z_TYPE_P(object) != IS_OBJECT) { if (Z_TYPE_P(object) != IS_STRING) { ZVAL_NULL(result); php_error_docref(NULL TSRMLS_CC, E_WARNING, "zephir_get_class_ns expects an object"); return; } } if (Z_TYPE_P(object) == IS_OBJECT) { ce = Z_OBJCE_P(object); class_name = ce->name; class_length = ce->name_length; } else { class_name = Z_STRVAL_P(object); class_length = Z_STRLEN_P(object); } if (!class_length) { ZVAL_NULL(result); return; } i = class_length; cursor = (char *) (class_name + class_length - 1); while (i > 0) { if ((*cursor) == '\\') { found = 1; break; } cursor--; i--; } if (found) { Z_STRLEN_P(result) = class_length - i; Z_STRVAL_P(result) = (char *) emalloc(class_length - i + 1); memcpy(Z_STRVAL_P(result), class_name + i, class_length - i); Z_STRVAL_P(result)[Z_STRLEN_P(result)] = 0; Z_TYPE_P(result) = IS_STRING; } else { ZVAL_STRINGL(result, class_name, class_length, 1); } if (lower) { zend_str_tolower(Z_STRVAL_P(result), Z_STRLEN_P(result)); } } /** * Returns a namespace from a class name */ void zephir_get_ns_class(zval *result, zval *object, int lower TSRMLS_DC) { zend_class_entry *ce; int found = 0; unsigned int i, j, class_length; const char *cursor, *class_name; if (Z_TYPE_P(object) != IS_OBJECT) { if (Z_TYPE_P(object) != IS_STRING) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "zephir_get_ns_class expects an object"); ZVAL_NULL(result); return; } } if (Z_TYPE_P(object) == IS_OBJECT) { ce = Z_OBJCE_P(object); class_name = ce->name; class_length = ce->name_length; } else { class_name = Z_STRVAL_P(object); class_length = Z_STRLEN_P(object); } if (!class_length) { ZVAL_NULL(result); return; } j = 0; i = class_length; cursor = (char *) (class_name + class_length - 1); while (i > 0) { if ((*cursor) == '\\') { found = 1; break; } cursor--; i--; j++; } if (j > 0) { if (found) { Z_STRLEN_P(result) = class_length - j - 1; Z_STRVAL_P(result) = (char *) emalloc(class_length - j); memcpy(Z_STRVAL_P(result), class_name, class_length - j - 1); Z_STRVAL_P(result)[Z_STRLEN_P(result)] = 0; Z_TYPE_P(result) = IS_STRING; } else { ZVAL_EMPTY_STRING(result); } if (lower) { zend_str_tolower(Z_STRVAL_P(result), Z_STRLEN_P(result)); } } else { ZVAL_NULL(result); } } /** * Returns the called in class in the current scope */ void zephir_get_called_class(zval *return_value TSRMLS_DC) { if (EG(called_scope)) { RETURN_STRINGL(EG(called_scope)->name, EG(called_scope)->name_length, 1); } if (!EG(scope)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "zephir_get_called_class() called from outside a class"); } } /** * Fetches a zend class entry from a zval value */ zend_class_entry *zephir_fetch_class(const zval *class_name TSRMLS_DC) { if (Z_TYPE_P(class_name) == IS_STRING) { return zend_fetch_class(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC); } php_error_docref(NULL TSRMLS_CC, E_WARNING, "class name must be a string"); return zend_fetch_class("stdclass", strlen("stdclass"), ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC); } zend_class_entry* zephir_fetch_self_class(TSRMLS_D) { return zend_fetch_class(NULL, 0, ZEND_FETCH_CLASS_SELF TSRMLS_CC); } zend_class_entry* zephir_fetch_parent_class(TSRMLS_D) { return zend_fetch_class(NULL, 0, ZEND_FETCH_CLASS_PARENT TSRMLS_CC); } zend_class_entry* zephir_fetch_static_class(TSRMLS_D) { return zend_fetch_class(NULL, 0, ZEND_FETCH_CLASS_STATIC TSRMLS_CC); } /** * Checks if a class exist */ int zephir_class_exists(const zval *class_name, int autoload TSRMLS_DC) { zend_class_entry **ce; if (Z_TYPE_P(class_name) == IS_STRING) { if (zend_lookup_class(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), &ce TSRMLS_CC) == SUCCESS) { #if PHP_VERSION_ID < 50400 return (((*ce)->ce_flags & ZEND_ACC_INTERFACE) == 0); #else return ((*ce)->ce_flags & (ZEND_ACC_INTERFACE | (ZEND_ACC_TRAIT - ZEND_ACC_EXPLICIT_ABSTRACT_CLASS))) == 0; #endif } return 0; } php_error_docref(NULL TSRMLS_CC, E_WARNING, "class name must be a string"); return 0; } /** * Checks if a interface exist */ int zephir_interface_exists(const zval *class_name, int autoload TSRMLS_DC) { zend_class_entry **ce; if (Z_TYPE_P(class_name) == IS_STRING) { if (zend_lookup_class(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), &ce TSRMLS_CC) == SUCCESS) { return (((*ce)->ce_flags & ZEND_ACC_INTERFACE) > 0); } return 0; } php_error_docref(NULL TSRMLS_CC, E_WARNING, "interface name must be a string"); return 0; } /** * Clones an object from obj to destination */ int zephir_clone(zval *destination, zval *obj TSRMLS_DC) { int status = SUCCESS; zend_class_entry *ce; zend_object_clone_obj_t clone_call; if (Z_TYPE_P(obj) != IS_OBJECT) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "__clone method called on non-object"); status = FAILURE; } else { ce = Z_OBJCE_P(obj); clone_call = Z_OBJ_HT_P(obj)->clone_obj; if (!clone_call) { if (ce) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "Trying to clone an uncloneable object of class %s", ce->name); } else { php_error_docref(NULL TSRMLS_CC, E_ERROR, "Trying to clone an uncloneable object"); } status = FAILURE; } else { if (!EG(exception)) { Z_OBJVAL_P(destination) = clone_call(obj TSRMLS_CC); Z_TYPE_P(destination) = IS_OBJECT; Z_SET_REFCOUNT_P(destination, 1); Z_UNSET_ISREF_P(destination); if (EG(exception)) { zval_ptr_dtor(&destination); } } } } return status; } /** * Checks if property exists on object */ int zephir_isset_property_quick(zval *object, const char *property_name, unsigned int property_length, unsigned long hash TSRMLS_DC) { if (Z_TYPE_P(object) == IS_OBJECT) { if (likely(zephir_hash_quick_exists(&Z_OBJCE_P(object)->properties_info, property_name, property_length, hash))) { return 1; } else { return zephir_hash_quick_exists(Z_OBJ_HT_P(object)->get_properties(object TSRMLS_CC), property_name, property_length, hash); } } return 0; } /** * Checks if property exists on object */ int zephir_isset_property(zval *object, const char *property_name, unsigned int property_length TSRMLS_DC) { return zephir_isset_property_quick(object, property_name, property_length, zend_inline_hash_func(property_name, property_length) TSRMLS_CC); } /** * Checks if string property exists on object */ int zephir_isset_property_zval(zval *object, const zval *property TSRMLS_DC) { unsigned long hash; if (Z_TYPE_P(object) == IS_OBJECT) { if (Z_TYPE_P(property) == IS_STRING) { hash = zend_inline_hash_func(Z_STRVAL_P(property), Z_STRLEN_P(property) + 1); if (likely(zephir_hash_quick_exists(&Z_OBJCE_P(object)->properties_info, Z_STRVAL_P(property), Z_STRLEN_P(property) + 1, hash))) { return 1; } else { return zephir_hash_quick_exists(Z_OBJ_HT_P(object)->get_properties(object TSRMLS_CC), Z_STRVAL_P(property), Z_STRLEN_P(property) + 1, hash); } } } return 0; } /* * Lookup exact class where a property is defined (precomputed key) * */ static inline zend_class_entry *zephir_lookup_class_ce_quick(zend_class_entry *ce, const char *property_name, zend_uint property_length, ulong hash TSRMLS_DC) { zend_class_entry *original_ce = ce; while (ce) { if (zephir_hash_quick_exists(&ce->properties_info, property_name, property_length + 1, hash)) { return ce; } ce = ce->parent; } return original_ce; } /** * Lookup exact class where a property is defined * */ static inline zend_class_entry *zephir_lookup_class_ce(zend_class_entry *ce, const char *property_name, unsigned int property_length TSRMLS_DC) { return zephir_lookup_class_ce_quick(ce, property_name, property_length, zend_inline_hash_func(property_name, property_length + 1) TSRMLS_CC); } /** * Reads a property from an object */ int zephir_read_property(zval **result, zval *object, const char *property_name, zend_uint property_length, int silent TSRMLS_DC) { zval *property; zend_class_entry *ce, *old_scope; if (Z_TYPE_P(object) != IS_OBJECT) { if (silent == PH_NOISY) { php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Trying to get property \"%s\" of non-object", property_name); } ALLOC_INIT_ZVAL(*result); ZVAL_NULL(*result); return FAILURE; } ce = Z_OBJCE_P(object); if (ce->parent) { ce = zephir_lookup_class_ce(ce, property_name, property_length TSRMLS_CC); } old_scope = EG(scope); EG(scope) = ce; if (!Z_OBJ_HT_P(object)->read_property) { #if PHP_VERSION_ID < 50400 char *class_name; #else const char *class_name; #endif zend_uint class_name_len; zend_get_object_classname(object, &class_name, &class_name_len TSRMLS_CC); zend_error(E_CORE_ERROR, "Property %s of class %s cannot be read", property_name, class_name); } MAKE_STD_ZVAL(property); ZVAL_STRINGL(property, property_name, property_length, 0); #if PHP_VERSION_ID < 50400 *result = Z_OBJ_HT_P(object)->read_property(object, property, silent ? BP_VAR_IS : BP_VAR_R TSRMLS_CC); #else *result = Z_OBJ_HT_P(object)->read_property(object, property, silent ? BP_VAR_IS : BP_VAR_R, 0 TSRMLS_CC); #endif Z_ADDREF_PP(result); if (Z_REFCOUNT_P(property) > 1) { ZVAL_STRINGL(property, property_name, property_length, 1); } else { ZVAL_NULL(property); } zval_ptr_dtor(&property); EG(scope) = old_scope; return SUCCESS; } zval* zephir_fetch_property_this_quick(zval *object, const char *property_name, zend_uint property_length, ulong key, int silent TSRMLS_DC) { zval **zv = NULL; zend_object *zobj; zend_property_info *property_info; zend_class_entry *ce, *old_scope; if (likely(Z_TYPE_P(object) == IS_OBJECT)) { ce = Z_OBJCE_P(object); if (ce->parent) { ce = zephir_lookup_class_ce_quick(ce, property_name, property_length, key TSRMLS_CC); } old_scope = EG(scope); EG(scope) = ce; zobj = zend_objects_get_address(object TSRMLS_CC); if (zephir_hash_quick_find(&ce->properties_info, property_name, property_length + 1, key, (void **) &property_info) == SUCCESS) { #if PHP_VERSION_ID < 50400 if (zephir_hash_quick_find(zobj->properties, property_info->name, property_info->name_length + 1, property_info->h, (void **) &zv) == SUCCESS) { EG(scope) = old_scope; return *zv; } #else int flag; if (EXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0) && property_info->offset >= 0) { if (zobj->properties) { zv = (zval**) zobj->properties_table[property_info->offset]; flag = (zv == NULL) ? 1 : 0; } else { zv = &zobj->properties_table[property_info->offset]; flag = (*zv == NULL) ? 1 : 0; } } else if (UNEXPECTED(!zobj->properties)) { flag = 1; } else if (UNEXPECTED(zephir_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &zv) == FAILURE)) { flag = 2; } else { flag = 0; } if (unlikely(flag) && zobj->properties) { if ( (flag == 2 || zephir_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &zv) == FAILURE) && zv && *zv ) { flag = 0; } } if (likely(!flag)) { EG(scope) = old_scope; return *zv; } #endif } EG(scope) = old_scope; } else { if (silent == PH_NOISY) { php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Trying to get property \"%s\" of non-object", property_name); } } return NULL; } /** * Returns an object's member */ int zephir_return_property_quick(zval *return_value, zval **return_value_ptr, zval *object, char *property_name, unsigned int property_length, unsigned long key TSRMLS_DC) { zval **zv; zend_object *zobj; zend_property_info *property_info; zend_class_entry *ce, *old_scope; if (likely(Z_TYPE_P(object) == IS_OBJECT)) { ce = Z_OBJCE_P(object); if (ce->parent) { ce = zephir_lookup_class_ce_quick(ce, property_name, property_length, key TSRMLS_CC); } old_scope = EG(scope); EG(scope) = ce; zobj = zend_objects_get_address(object TSRMLS_CC); if (zephir_hash_quick_find(&ce->properties_info, property_name, property_length + 1, key, (void **) &property_info) == SUCCESS) { #if PHP_VERSION_ID < 50400 if (zephir_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &zv) == SUCCESS) { EG(scope) = old_scope; if (return_value_ptr) { zval_ptr_dtor(return_value_ptr); Z_ADDREF_PP(zv); *return_value_ptr = *zv; } else { ZVAL_ZVAL(return_value, *zv, 1, 0); } return SUCCESS; } #else int flag; if (EXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0) && property_info->offset >= 0) { if (zobj->properties) { zv = (zval**) zobj->properties_table[property_info->offset]; flag = (zv == NULL) ? 1 : 0; } else { zv = &zobj->properties_table[property_info->offset]; flag = (*zv == NULL) ? 1 : 0; } } else if (UNEXPECTED(!zobj->properties)) { flag = 1; } else if (UNEXPECTED(zephir_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &zv) == FAILURE)) { flag = 2; } else { flag = 0; } if (unlikely(flag) && zobj->properties) { if ( (flag == 2 || zephir_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &zv) == FAILURE) && zv && *zv ) { flag = 0; } } if (likely(!flag)) { EG(scope) = old_scope; if (return_value_ptr) { zval_ptr_dtor(return_value_ptr); Z_ADDREF_PP(zv); *return_value_ptr = *zv; } else { ZVAL_ZVAL(return_value, *zv, 1, 0); } return SUCCESS; } #endif } EG(scope) = old_scope; } else { php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Trying to get property \"%s\" of non-object", property_name); } ZVAL_NULL(return_value); return FAILURE; } /** * Returns an object's member */ int zephir_return_property(zval *return_value, zval **return_value_ptr, zval *object, char *property_name, unsigned int property_length TSRMLS_DC) { return zephir_return_property_quick(return_value, return_value_ptr, object, property_name, property_length, zend_inline_hash_func(property_name, property_length + 1) TSRMLS_CC); } /** * Reads a property from an object */ int zephir_read_property_zval(zval **result, zval *object, zval *property, int flags TSRMLS_DC) { if (unlikely(Z_TYPE_P(property) != IS_STRING)) { if ((flags & PH_NOISY) == PH_NOISY) { php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot access empty property %d", Z_TYPE_P(property)); } *result = ZEPHIR_GLOBAL(global_null); Z_ADDREF_P(*result); return FAILURE; } return zephir_read_property(result, object, Z_STRVAL_P(property), Z_STRLEN_P(property), flags TSRMLS_CC); } /** * Checks whether obj is an object and updates property with long value */ int zephir_update_property_long(zval *object, char *property_name, unsigned int property_length, long value TSRMLS_DC) { zval *v; ALLOC_ZVAL(v); Z_UNSET_ISREF_P(v); Z_SET_REFCOUNT_P(v, 0); ZVAL_LONG(v, value); return zephir_update_property_zval(object, property_name, property_length, v TSRMLS_CC); } /** * Checks whether obj is an object and updates property with string value */ int zephir_update_property_string(zval *object, char *property_name, unsigned int property_length, char *str, unsigned int str_length TSRMLS_DC) { zval *value; int res; ALLOC_ZVAL(value); Z_UNSET_ISREF_P(value); Z_SET_REFCOUNT_P(value, 0); ZVAL_STRINGL(value, str, str_length, 1); res = zephir_update_property_zval(object, property_name, property_length, value TSRMLS_CC); if (res == SUCCESS) { return SUCCESS; } return FAILURE; } /** * Checks whether obj is an object and updates property with bool value */ int zephir_update_property_bool(zval *object, char *property_name, unsigned int property_length, int value TSRMLS_DC) { return zephir_update_property_zval(object, property_name, property_length, value ? ZEPHIR_GLOBAL(global_true) : ZEPHIR_GLOBAL(global_false) TSRMLS_CC); } /** * Checks whether obj is an object and updates property with null value */ int zephir_update_property_null(zval *object, char *property_name, unsigned int property_length TSRMLS_DC) { return zephir_update_property_zval(object, property_name, property_length, ZEPHIR_GLOBAL(global_null) TSRMLS_CC); } /** * Checks whether obj is an object and updates property with another zval */ int zephir_update_property_zval(zval *object, const char *property_name, unsigned int property_length, zval *value TSRMLS_DC){ zend_class_entry *ce, *old_scope; zval *property; old_scope = EG(scope); if (Z_TYPE_P(object) != IS_OBJECT) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attempt to assign property of non-object"); return FAILURE; } ce = Z_OBJCE_P(object); if (ce->parent) { ce = zephir_lookup_class_ce(ce, property_name, property_length TSRMLS_CC); } EG(scope) = ce; if (!Z_OBJ_HT_P(object)->write_property) { #if PHP_VERSION_ID < 50400 char *class_name; #else const char *class_name; #endif zend_uint class_name_len; zend_get_object_classname(object, &class_name, &class_name_len TSRMLS_CC); zend_error(E_CORE_ERROR, "Property %s of class %s cannot be updated", property_name, class_name); } MAKE_STD_ZVAL(property); ZVAL_STRINGL(property, property_name, property_length, 0); #if PHP_VERSION_ID < 50400 Z_OBJ_HT_P(object)->write_property(object, property, value TSRMLS_CC); #else Z_OBJ_HT_P(object)->write_property(object, property, value, 0 TSRMLS_CC); #endif if (Z_REFCOUNT_P(property) > 1) { ZVAL_STRINGL(property, property_name, property_length, 1); } else { ZVAL_NULL(property); } zval_ptr_dtor(&property); EG(scope) = old_scope; return SUCCESS; } /** * Updates properties on this_ptr (quick) * Variables must be defined in the class definition. This function ignores magic methods or dynamic properties */ int zephir_update_property_this_quick(zval *object, const char *property_name, zend_uint property_length, zval *value, ulong key TSRMLS_DC){ zend_class_entry *ce, *old_scope; if (unlikely(Z_TYPE_P(object) != IS_OBJECT)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attempt to assign property of non-object"); return FAILURE; } ce = Z_OBJCE_P(object); if (ce->parent) { ce = zephir_lookup_class_ce_quick(ce, property_name, property_length, key TSRMLS_CC); } old_scope = EG(scope); EG(scope) = ce; #if PHP_VERSION_ID < 50400 { zval *property; if (!Z_OBJ_HT_P(object)->write_property) { EG(scope) = old_scope; php_error_docref(NULL TSRMLS_CC, E_WARNING, "Property %s of class %s cannot be updated", property_name, ce->name); return FAILURE; } MAKE_STD_ZVAL(property); ZVAL_STRINGL(property, property_name, property_length, 0); Z_OBJ_HT_P(object)->write_property(object, property, value TSRMLS_CC); if (Z_REFCOUNT_P(property) > 1) { ZVAL_STRINGL(property, property_name, property_length, 1); } else { ZVAL_NULL(property); } zval_ptr_dtor(&property); } #else { zend_object *zobj; zval **variable_ptr; zend_property_info *property_info; zobj = zend_objects_get_address(object TSRMLS_CC); if (zephir_hash_quick_find(&ce->properties_info, property_name, property_length + 1, key, (void **) &property_info) == SUCCESS) { assert(property_info != NULL); /** This is as zend_std_write_property, but we're not interesed in validate properties visibility */ if (property_info->offset >= 0 ? (zobj->properties ? ((variable_ptr = (zval**) zobj->properties_table[property_info->offset]) != NULL) : (*(variable_ptr = &zobj->properties_table[property_info->offset]) != NULL)) : (EXPECTED(zobj->properties != NULL) && EXPECTED(zephir_hash_quick_find(zobj->properties, property_info->name, property_info->name_length + 1, property_info->h, (void **) &variable_ptr) == SUCCESS))) { if (EXPECTED(*variable_ptr != value)) { /* if we are assigning reference, we shouldn't move it, but instead assign variable to the same pointer */ if (PZVAL_IS_REF(*variable_ptr)) { zval garbage = **variable_ptr; /* old value should be destroyed */ /* To check: can't *variable_ptr be some system variable like error_zval here? */ Z_TYPE_PP(variable_ptr) = Z_TYPE_P(value); (*variable_ptr)->value = value->value; if (Z_REFCOUNT_P(value) > 0) { zval_copy_ctor(*variable_ptr); } else { efree(value); } zval_dtor(&garbage); } else { zval *garbage = *variable_ptr; /* if we assign referenced variable, we should separate it */ Z_ADDREF_P(value); if (PZVAL_IS_REF(value)) { SEPARATE_ZVAL(&value); } *variable_ptr = value; zval_ptr_dtor(&garbage); } } } } } #endif EG(scope) = old_scope; return SUCCESS; } /** * Updates properties on this_ptr * Variables must be defined in the class definition. This function ignores magic methods or dynamic properties */ int zephir_update_property_this(zval *object, char *property_name, unsigned int property_length, zval *value TSRMLS_DC) { return zephir_update_property_this_quick(object, property_name, property_length, value, zend_inline_hash_func(property_name, property_length + 1) TSRMLS_CC); } /** * Checks whether obj is an object and updates zval property with another zval */ int zephir_update_property_zval_zval(zval *object, zval *property, zval *value TSRMLS_DC) { if (Z_TYPE_P(property) != IS_STRING) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Property should be string"); return FAILURE; } return zephir_update_property_zval(object, Z_STRVAL_P(property), Z_STRLEN_P(property), value TSRMLS_CC); } /** * Updates an array property */ int zephir_update_property_array(zval *object, const char *property, zend_uint property_length, const zval *index, zval *value TSRMLS_DC) { zval *tmp; int separated = 0; if (Z_TYPE_P(object) == IS_OBJECT) { zephir_read_property(&tmp, object, property, property_length, PH_NOISY TSRMLS_CC); Z_DELREF_P(tmp); /** Separation only when refcount > 1 */ if (Z_REFCOUNT_P(tmp) > 1) { if (!Z_ISREF_P(tmp)) { zval *new_zv; ALLOC_ZVAL(new_zv); INIT_PZVAL_COPY(new_zv, tmp); tmp = new_zv; zval_copy_ctor(new_zv); Z_SET_REFCOUNT_P(tmp, 0); Z_UNSET_ISREF_P(tmp); separated = 1; } } /** Convert the value to array if not is an array */ if (Z_TYPE_P(tmp) != IS_ARRAY) { if (separated) { convert_to_array(tmp); } else { zval *new_zv; ALLOC_ZVAL(new_zv); INIT_PZVAL_COPY(new_zv, tmp); tmp = new_zv; zval_copy_ctor(new_zv); Z_SET_REFCOUNT_P(tmp, 0); Z_UNSET_ISREF_P(tmp); array_init(tmp); separated = 1; } } Z_ADDREF_P(value); if (Z_TYPE_P(index) == IS_STRING) { zend_symtable_update(Z_ARRVAL_P(tmp), Z_STRVAL_P(index), Z_STRLEN_P(index) + 1, &value, sizeof(zval*), NULL); } else if (Z_TYPE_P(index) == IS_LONG) { zend_hash_index_update(Z_ARRVAL_P(tmp), Z_LVAL_P(index), &value, sizeof(zval *), NULL); } else if (Z_TYPE_P(index) == IS_NULL) { zend_hash_next_index_insert(Z_ARRVAL_P(tmp), (void**)&value, sizeof(zval*), NULL); } if (separated) { zephir_update_property_zval(object, property, property_length, tmp TSRMLS_CC); } } return SUCCESS; } /** * Multiple array-offset update */ int zephir_update_property_array_multi(zval *object, const char *property, zend_uint property_length, zval **value TSRMLS_DC, const char *types, int types_length, int types_count, ...) { va_list ap; zval *tmp_arr; int separated = 0; if (Z_TYPE_P(object) == IS_OBJECT) { zephir_read_property(&tmp_arr, object, property, property_length, PH_NOISY TSRMLS_CC); Z_DELREF_P(tmp_arr); /** Separation only when refcount > 1 */ if (Z_REFCOUNT_P(tmp_arr) > 1) { if (!Z_ISREF_P(tmp_arr)) { zval *new_zv; ALLOC_ZVAL(new_zv); INIT_PZVAL_COPY(new_zv, tmp_arr); tmp_arr = new_zv; zval_copy_ctor(new_zv); Z_SET_REFCOUNT_P(tmp_arr, 0); Z_UNSET_ISREF_P(tmp_arr); separated = 1; } } /** Convert the value to array if not is an array */ if (Z_TYPE_P(tmp_arr) != IS_ARRAY) { if (separated) { convert_to_array(tmp_arr); } else { zval *new_zv; ALLOC_ZVAL(new_zv); INIT_PZVAL_COPY(new_zv, tmp_arr); tmp_arr = new_zv; zval_copy_ctor(new_zv); Z_SET_REFCOUNT_P(tmp_arr, 0); Z_UNSET_ISREF_P(tmp_arr); array_init(tmp_arr); separated = 1; } } va_start(ap, types_count); zephir_array_update_multi_ex(&tmp_arr, value, types, types_length, types_count, ap TSRMLS_CC); va_end(ap); if (separated) { zephir_update_property_zval(object, property, property_length, tmp_arr TSRMLS_CC); } } return SUCCESS; } /** * Updates an array property using a string index */ int zephir_update_property_array_string(zval *object, char *property, unsigned int property_length, char *index, unsigned int index_length, zval *value TSRMLS_DC) { zval *tmp; int separated = 0; if (likely(Z_TYPE_P(object) == IS_OBJECT)) { zephir_read_property(&tmp, object, property, property_length, PH_NOISY_CC); Z_DELREF_P(tmp); /** Separation only when refcount > 1 */ if (Z_REFCOUNT_P(tmp) > 1) { if (!Z_ISREF_P(tmp)) { zval *new_zv; ALLOC_ZVAL(new_zv); INIT_PZVAL_COPY(new_zv, tmp); tmp = new_zv; zval_copy_ctor(new_zv); Z_SET_REFCOUNT_P(tmp, 0); Z_UNSET_ISREF_P(tmp); separated = 1; } } /** Convert the value to array if not is an array */ if (Z_TYPE_P(tmp) != IS_ARRAY) { if (separated) { convert_to_array(tmp); } else { zval *new_zv; ALLOC_ZVAL(new_zv); INIT_PZVAL_COPY(new_zv, tmp); tmp = new_zv; zval_copy_ctor(new_zv); Z_SET_REFCOUNT_P(tmp, 0); Z_UNSET_ISREF_P(tmp); array_init(tmp); separated = 1; } } Z_ADDREF_P(value); zend_hash_update(Z_ARRVAL_P(tmp), index, index_length, &value, sizeof(zval *), NULL); if (separated) { zephir_update_property_zval(object, property, property_length, tmp TSRMLS_CC); } } return SUCCESS; } /** * Appends a zval value to an array property */ int zephir_update_property_array_append(zval *object, char *property, unsigned int property_length, zval *value TSRMLS_DC) { zval *tmp; int separated = 0; if (Z_TYPE_P(object) != IS_OBJECT) { return SUCCESS; } zephir_read_property(&tmp, object, property, property_length, PH_NOISY_CC); Z_DELREF_P(tmp); /** Separation only when refcount > 1 */ if (Z_REFCOUNT_P(tmp) > 1) { if (!Z_ISREF_P(tmp)) { zval *new_zv; ALLOC_ZVAL(new_zv); INIT_PZVAL_COPY(new_zv, tmp); tmp = new_zv; zval_copy_ctor(new_zv); Z_SET_REFCOUNT_P(tmp, 0); Z_UNSET_ISREF_P(tmp); separated = 1; } } /** Convert the value to array if not is an array */ if (Z_TYPE_P(tmp) != IS_ARRAY) { if (separated) { convert_to_array(tmp); } else { zval *new_zv; ALLOC_ZVAL(new_zv); INIT_PZVAL_COPY(new_zv, tmp); tmp = new_zv; zval_copy_ctor(new_zv); Z_SET_REFCOUNT_P(tmp, 0); Z_UNSET_ISREF_P(tmp); array_init(tmp); separated = 1; } } Z_ADDREF_P(value); add_next_index_zval(tmp, value); if (separated) { zephir_update_property_zval(object, property, property_length, tmp TSRMLS_CC); } return SUCCESS; } /** * Intializes an object property with an empty array */ int zephir_update_property_empty_array(zend_class_entry *ce, zval *object, char *property_name, unsigned int property_length TSRMLS_DC) { zval *empty_array; int res; ALLOC_INIT_ZVAL(empty_array); array_init(empty_array); res = zephir_update_property_zval(object, property_name, property_length, empty_array TSRMLS_CC); zval_ptr_dtor(&empty_array); return res; } int zephir_unset_property(zval* object, const char* name TSRMLS_DC) { if (Z_TYPE_P(object) == IS_OBJECT) { zval member; zend_class_entry *old_scope; INIT_PZVAL(&member); ZVAL_STRING(&member, name, 0); old_scope = EG(scope); EG(scope) = Z_OBJCE_P(object); #if PHP_VERSION_ID < 50400 Z_OBJ_HT_P(object)->unset_property(object, &member TSRMLS_CC); #else Z_OBJ_HT_P(object)->unset_property(object, &member, 0 TSRMLS_CC); #endif EG(scope) = old_scope; return SUCCESS; } return FAILURE; } /** * Unsets an index in an array property */ int zephir_unset_property_array(zval *object, char *property, unsigned int property_length, zval *index TSRMLS_DC) { zval *tmp; int separated = 0; if (Z_TYPE_P(object) == IS_OBJECT) { zephir_read_property(&tmp, object, property, property_length, PH_NOISY_CC); Z_DELREF_P(tmp); /** Separation only when refcount > 1 */ if (Z_REFCOUNT_P(tmp) > 1) { if (!Z_ISREF_P(tmp)) { zval *new_zv; ALLOC_ZVAL(new_zv); INIT_PZVAL_COPY(new_zv, tmp); tmp = new_zv; zval_copy_ctor(new_zv); Z_SET_REFCOUNT_P(tmp, 0); Z_UNSET_ISREF_P(tmp); separated = 1; } } zephir_array_unset(&tmp, index, PH_SEPARATE); if (separated) { zephir_update_property_zval(object, property, property_length, tmp TSRMLS_CC); } } return SUCCESS; } /** * Check if a method is implemented on certain object */ int zephir_method_exists(const zval *object, const zval *method_name TSRMLS_DC){ char *lcname = zend_str_tolower_dup(Z_STRVAL_P(method_name), Z_STRLEN_P(method_name)); int res = zephir_method_exists_ex(object, lcname, Z_STRLEN_P(method_name) + 1 TSRMLS_CC); efree(lcname); return res; } /** * Check if method exists on certain object using explicit char param * * @param object * @param method_name * @param method_length strlen(method_name)+1 */ int zephir_method_exists_ex(const zval *object, const char *method_name, unsigned int method_len TSRMLS_DC){ return zephir_method_quick_exists_ex(object, method_name, method_len, zend_inline_hash_func(method_name, method_len) TSRMLS_CC); } /** * Check if method exists on certain object using explicit char param */ int zephir_method_quick_exists_ex(const zval *object, const char *method_name, unsigned int method_len, unsigned long hash TSRMLS_DC){ zend_class_entry *ce; if (likely(Z_TYPE_P(object) == IS_OBJECT)) { ce = Z_OBJCE_P(object); } else { if (Z_TYPE_P(object) == IS_STRING) { ce = zend_fetch_class(Z_STRVAL_P(object), Z_STRLEN_P(object), ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC); } else { return FAILURE; } } while (ce) { if (zephir_hash_quick_exists(&ce->function_table, method_name, method_len, hash)) { return SUCCESS; } ce = ce->parent; } return FAILURE; } zval* zephir_fetch_static_property_ce(zend_class_entry *ce, const char *property, int len TSRMLS_DC) { assert(ce != NULL); return zend_read_static_property(ce, property, len, (zend_bool) ZEND_FETCH_CLASS_SILENT TSRMLS_CC); } int zephir_read_static_property_ce(zval **result, zend_class_entry *ce, const char *property, int len TSRMLS_DC) { zval *tmp; tmp = zephir_fetch_static_property_ce(ce, property, len TSRMLS_CC); if (tmp) { if (!Z_ISREF_P(tmp)) { *result = tmp; Z_ADDREF_PP(result); } else { ALLOC_INIT_ZVAL(*result); ZVAL_ZVAL(*result, tmp, 1, 0); } return SUCCESS; } ALLOC_INIT_ZVAL(*result); return FAILURE; } #if PHP_VERSION_ID >= 50400 static zval **zephir_std_get_static_property(zend_class_entry *ce, const char *property_name, int property_name_len, ulong hash_value, zend_bool silent, zend_property_info ** property_info TSRMLS_DC) { zend_property_info *temp_property_info; if (!hash_value) { hash_value = zend_hash_func(property_name, property_name_len + 1); } if (!property_info || !*property_info) { if (UNEXPECTED(zend_hash_quick_find(&ce->properties_info, property_name, property_name_len + 1, hash_value, (void **) &temp_property_info)==FAILURE)) { if (!silent) { zend_error_noreturn(E_ERROR, "Access to undeclared static property: %s::$%s", ce->name, property_name); } return NULL; } #ifndef ZEPHIR_RELEASE /*if (UNEXPECTED(!zend_verify_property_access(temp_property_info, ce TSRMLS_CC))) { if (!silent) { zend_error_noreturn(E_ERROR, "Cannot access %s property %s::$%s", zend_visibility_string(temp_property_info->flags), ce->name, property_name); } return NULL; } if (UNEXPECTED((temp_property_info->flags & ZEND_ACC_STATIC) == 0)) { if (!silent) { zend_error_noreturn(E_ERROR, "Access to undeclared static property: %s::$%s", ce->name, property_name); } return NULL; }*/ #endif zend_update_class_constants(ce TSRMLS_CC); if (property_info) { *property_info = temp_property_info; } } else { temp_property_info = *property_info; } if (UNEXPECTED(CE_STATIC_MEMBERS(ce) == NULL) || UNEXPECTED(CE_STATIC_MEMBERS(ce)[temp_property_info->offset] == NULL)) { if (!silent) { zend_error_noreturn(E_ERROR, "Access to undeclared static property: %s::$%s", ce->name, property_name); } return NULL; } return &CE_STATIC_MEMBERS(ce)[temp_property_info->offset]; } #endif static int zephir_update_static_property_ex(zend_class_entry *scope, const char *name, int name_length, zval **value, zend_property_info **property_info TSRMLS_DC) { zval **property; zval *tmp, **safe_value; zend_zephir_globals_def *zephir_globals_ptr = ZEPHIR_VGLOBAL; zend_class_entry *old_scope = EG(scope); /** * We have to protect super globals to avoid them make converted to references */ if (*value == zephir_globals_ptr->global_null) { ALLOC_ZVAL(tmp); Z_UNSET_ISREF_P(tmp); Z_SET_REFCOUNT_P(tmp, 0); ZVAL_NULL(tmp); safe_value = &tmp; } else { if (*value == zephir_globals_ptr->global_true) { ALLOC_ZVAL(tmp); Z_UNSET_ISREF_P(tmp); Z_SET_REFCOUNT_P(tmp, 0); ZVAL_BOOL(tmp, 1); safe_value = &tmp; } else { if (*value == zephir_globals_ptr->global_false) { ALLOC_ZVAL(tmp); Z_UNSET_ISREF_P(tmp); Z_SET_REFCOUNT_P(tmp, 0); ZVAL_BOOL(tmp, 0); safe_value = &tmp; } else { safe_value = value; } } } EG(scope) = scope; #if PHP_VERSION_ID < 50400 property = zend_std_get_static_property(scope, name, name_length, 0 TSRMLS_CC); #else property = zephir_std_get_static_property(scope, name, name_length, zend_inline_hash_func(name, name_length + 1), 0, property_info TSRMLS_CC); #endif EG(scope) = old_scope; if (!property) { return FAILURE; } else { if (*property != *safe_value) { if (PZVAL_IS_REF(*property)) { zval_dtor(*property); Z_TYPE_PP(property) = Z_TYPE_PP(safe_value); (*property)->value = (*safe_value)->value; if (Z_REFCOUNT_PP(safe_value) > 0) { zval_copy_ctor(*property); } else { efree(*safe_value); *safe_value = NULL; } } else { zval *garbage = *property; Z_ADDREF_PP(safe_value); if (Z_ISREF_PP(safe_value)) { SEPARATE_ZVAL(safe_value); } *property = *safe_value; zval_ptr_dtor(&garbage); } } return SUCCESS; } } /** * Query a static property value from a zend_class_entry */ int zephir_read_static_property(zval **result, const char *class_name, unsigned int class_length, char *property_name, unsigned int property_length TSRMLS_DC) { zend_class_entry **ce; if (zend_lookup_class(class_name, class_length, &ce TSRMLS_CC) == SUCCESS) { return zephir_read_static_property_ce(result, *ce, property_name, property_length TSRMLS_CC); } return FAILURE; } int zephir_update_static_property_ce(zend_class_entry *ce, const char *name, int len, zval **value TSRMLS_DC) { assert(ce != NULL); return zephir_update_static_property_ex(ce, name, len, value, NULL TSRMLS_CC); } int zephir_update_static_property_ce_cache(zend_class_entry *ce, const char *name, int len, zval **value, zend_property_info **property_info TSRMLS_DC) { assert(ce != NULL); return zephir_update_static_property_ex(ce, name, len, value, property_info TSRMLS_CC); } /* * Multiple array-offset update */ int zephir_update_static_property_array_multi_ce(zend_class_entry *ce, const char *property, zend_uint property_length, zval **value TSRMLS_DC, const char *types, int types_length, int types_count, ...) { va_list ap; zval *tmp_arr; int separated = 0; tmp_arr = zephir_fetch_static_property_ce(ce, property, property_length TSRMLS_CC); if (!tmp_arr) { ALLOC_INIT_ZVAL(tmp_arr); array_init(tmp_arr); separated = 1; } /** Separation only when refcount > 1 */ if (Z_REFCOUNT_P(tmp_arr) > 1) { if (!Z_ISREF_P(tmp_arr)) { zval *new_zv; ALLOC_ZVAL(new_zv); INIT_PZVAL_COPY(new_zv, tmp_arr); tmp_arr = new_zv; zval_copy_ctor(new_zv); Z_SET_REFCOUNT_P(tmp_arr, 0); Z_UNSET_ISREF_P(tmp_arr); separated = 1; } } /** Convert the value to array if not is an array */ if (Z_TYPE_P(tmp_arr) != IS_ARRAY) { if (separated) { convert_to_array(tmp_arr); } else { zval *new_zv; ALLOC_ZVAL(new_zv); INIT_PZVAL_COPY(new_zv, tmp_arr); tmp_arr = new_zv; zval_copy_ctor(new_zv); Z_SET_REFCOUNT_P(tmp_arr, 0); Z_UNSET_ISREF_P(tmp_arr); array_init(tmp_arr); separated = 1; } } va_start(ap, types_count); zephir_array_update_multi_ex(&tmp_arr, value, types, types_length, types_count, ap TSRMLS_CC); va_end(ap); if (separated) { zephir_update_static_property_ce(ce, property, property_length, &tmp_arr TSRMLS_CC); } return SUCCESS; } /** * Update a static property */ int zephir_update_static_property(const char *class_name, unsigned int class_length, char *name, unsigned int name_length, zval **value TSRMLS_DC){ zend_class_entry **ce; if (zend_lookup_class(class_name, class_length, &ce TSRMLS_CC) == SUCCESS) { return zephir_update_static_property_ce(*ce, name, name_length, value TSRMLS_CC); } return FAILURE; } int zephir_read_class_property(zval **result, int type, const char *property, int len TSRMLS_DC) { zend_class_entry *ce; type |= (ZEND_FETCH_CLASS_SILENT | ZEND_FETCH_CLASS_NO_AUTOLOAD); type &= ZEND_FETCH_CLASS_MASK; ce = zend_fetch_class(NULL, 0, type TSRMLS_CC); if (likely(ce != NULL)) { return zephir_read_static_property_ce(result, ce, property, len TSRMLS_CC); } return FAILURE; } /** * Creates a new instance dynamically. Call constructor without parameters */ int zephir_create_instance(zval *return_value, const zval *class_name TSRMLS_DC){ zend_class_entry *ce; if (Z_TYPE_P(class_name) != IS_STRING) { zephir_throw_exception_string(spl_ce_RuntimeException, SL("Invalid class name") TSRMLS_CC); return FAILURE; } ce = zend_fetch_class(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC); if (!ce) { ZVAL_NULL(return_value); return FAILURE; } object_init_ex(return_value, ce); if (zephir_has_constructor_ce(ce)) { return zephir_call_class_method_aparams(NULL, ce, zephir_fcall_method, return_value, SL("__construct"), NULL, 0, 0, NULL TSRMLS_CC); } return SUCCESS; } /** * Creates a new instance dynamically calling constructor with parameters */ int zephir_create_instance_params(zval *return_value, const zval *class_name, zval *params TSRMLS_DC){ int outcome; zend_class_entry *ce; if (Z_TYPE_P(class_name) != IS_STRING) { zephir_throw_exception_string(spl_ce_RuntimeException, SL("Invalid class name") TSRMLS_CC); return FAILURE; } if (Z_TYPE_P(params) != IS_ARRAY) { zephir_throw_exception_string(spl_ce_RuntimeException, SL("Instantiation parameters must be an array") TSRMLS_CC); return FAILURE; } ce = zend_fetch_class(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC); if (!ce) { ZVAL_NULL(return_value); return FAILURE; } object_init_ex(return_value, ce); outcome = SUCCESS; if (zephir_has_constructor_ce(ce)) { int param_count = zend_hash_num_elements(Z_ARRVAL_P(params)); zval *static_params[10]; zval **params_ptr, **params_arr = NULL; if (param_count > 0) { HashPosition pos; zval **item; int i = 0; if (likely(param_count) <= 10) { params_ptr = static_params; } else { params_arr = emalloc(param_count * sizeof(zval*)); params_ptr = &params; } for ( zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(params), &pos); zend_hash_get_current_data_ex(Z_ARRVAL_P(params), (void**) &item, &pos) == SUCCESS; zend_hash_move_forward_ex(Z_ARRVAL_P(params), &pos), ++i ) { params_ptr[i] = *item; } } else { params_ptr = NULL; } outcome = zephir_call_class_method_aparams(NULL, ce, zephir_fcall_method, return_value, SL("__construct"), NULL, 0, param_count, params_ptr TSRMLS_CC); if (unlikely(params_arr != NULL)) { efree(params_arr); } } return outcome; } /** * Increments an object property */ int zephir_property_incr(zval *object, char *property_name, unsigned int property_length TSRMLS_DC){ zval *tmp = NULL; zend_class_entry *ce; int separated = 0; if (Z_TYPE_P(object) != IS_OBJECT) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attempt to assign property of non-object"); return FAILURE; } ce = Z_OBJCE_P(object); if (ce->parent) { ce = zephir_lookup_class_ce(ce, property_name, property_length TSRMLS_CC); } zephir_read_property(&tmp, object, property_name, property_length, 0 TSRMLS_CC); if (tmp) { Z_DELREF_P(tmp); /** Separation only when refcount > 1 */ if (Z_REFCOUNT_P(tmp) > 1) { if (!Z_ISREF_P(tmp)) { zval *new_zv; ALLOC_ZVAL(new_zv); INIT_PZVAL_COPY(new_zv, tmp); tmp = new_zv; zval_copy_ctor(new_zv); Z_SET_REFCOUNT_P(tmp, 0); Z_UNSET_ISREF_P(tmp); separated = 1; } } zephir_increment(tmp); if (separated) { zephir_update_property_zval(object, property_name, property_length, tmp TSRMLS_CC); } } return SUCCESS; } /** * Decrements an object property */ int zephir_property_decr(zval *object, char *property_name, unsigned int property_length TSRMLS_DC){ zval *tmp = NULL; zend_class_entry *ce; int separated = 0; if (Z_TYPE_P(object) != IS_OBJECT) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attempt to assign property of non-object"); return FAILURE; } ce = Z_OBJCE_P(object); if (ce->parent) { ce = zephir_lookup_class_ce(ce, property_name, property_length TSRMLS_CC); } zephir_read_property(&tmp, object, property_name, property_length, 0 TSRMLS_CC); if (tmp) { Z_DELREF_P(tmp); /** Separation only when refcount > 1 */ if (Z_REFCOUNT_P(tmp) > 1) { if (!Z_ISREF_P(tmp)) { zval *new_zv; ALLOC_ZVAL(new_zv); INIT_PZVAL_COPY(new_zv, tmp); tmp = new_zv; zval_copy_ctor(new_zv); Z_SET_REFCOUNT_P(tmp, 0); Z_UNSET_ISREF_P(tmp); separated = 1; } } zephir_decrement(tmp); if (separated) { zephir_update_property_zval(object, property_name, property_length, tmp TSRMLS_CC); } } return SUCCESS; } /** * Fetches a property using a const char */ int zephir_fetch_property(zval **result, zval *object, const char *property_name, zend_uint property_length, int silent TSRMLS_DC) { if (zephir_isset_property(object, property_name, property_length + 1 TSRMLS_CC)) { zephir_read_property(result, object, property_name, property_length, 0 TSRMLS_CC); return 1; } *result = ZEPHIR_GLOBAL(global_null); Z_ADDREF_P(*result); return 0; } /** * Fetches a property using a zval property */ int zephir_fetch_property_zval(zval **result, zval *object, zval *property, int silent TSRMLS_DC) { if (unlikely(Z_TYPE_P(property) != IS_STRING)) { *result = ZEPHIR_GLOBAL(global_null); Z_ADDREF_P(*result); return 0; } if (zephir_isset_property(object, Z_STRVAL_P(property), Z_STRLEN_P(property) + 1 TSRMLS_CC)) { zephir_read_property(result, object, Z_STRVAL_P(property), Z_STRLEN_P(property), 0 TSRMLS_CC); return 1; } *result = ZEPHIR_GLOBAL(global_null); Z_ADDREF_P(*result); return 0; } /** * Creates a closure */ int zephir_create_closure_ex(zval *return_value, zval *this_ptr, zend_class_entry *ce, const char *method_name, zend_uint method_length TSRMLS_DC) { zend_function *function_ptr; if (zend_hash_find(&ce->function_table, method_name, method_length, (void**) &function_ptr) == FAILURE) { ZVAL_NULL(return_value); return FAILURE; } #if PHP_VERSION_ID < 50400 zend_create_closure(return_value, function_ptr TSRMLS_CC); #else zend_create_closure(return_value, function_ptr, ce, this_ptr TSRMLS_CC); #endif return SUCCESS; }