PHP Classes

File: vendor/pimple/pimple/ext/pimple/pimple.c

Recommend this page to a friend!
  Classes of Gavin Gordon Markowski   Helphp PHP Class Generator   vendor/pimple/pimple/ext/pimple/pimple.c   Download  
File: vendor/pimple/pimple/ext/pimple/pimple.c
Role: Auxiliary data
Content type: text/plain
Description: Auxiliary data
Class: Helphp PHP Class Generator
Generate classes from configuration parameters
Author: By
Last change:
Date: 2 years ago
Size: 29,231 bytes
 

Contents

Class file image Download
/* * This file is part of Pimple. * * Copyright (c) 2014 Fabien Potencier * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is furnished * to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "php.h" #include "php_ini.h" #include "ext/standard/info.h" #include "php_pimple.h" #include "pimple_compat.h" #include "zend_interfaces.h" #include "zend.h" #include "Zend/zend_closures.h" #include "ext/spl/spl_exceptions.h" #include "Zend/zend_exceptions.h" #include "main/php_output.h" #include "SAPI.h" static zend_class_entry *pimple_ce; static zend_object_handlers pimple_object_handlers; static zend_class_entry *pimple_closure_ce; static zend_class_entry *pimple_serviceprovider_ce; static zend_object_handlers pimple_closure_object_handlers; static zend_internal_function pimple_closure_invoker_function; #define FETCH_DIM_HANDLERS_VARS pimple_object *pimple_obj = NULL; \ ulong index; \ pimple_obj = (pimple_object *)zend_object_store_get_object(object TSRMLS_CC); \ #define PIMPLE_OBJECT_HANDLE_INHERITANCE_OBJECT_HANDLERS do { \ if (ce != pimple_ce) { \ zend_hash_find(&ce->function_table, ZEND_STRS("offsetget"), (void **)&function); \ if (function->common.scope != ce) { /* if the function is not defined in this actual class */ \ pimple_object_handlers.read_dimension = pimple_object_read_dimension; /* then overwrite the handler to use custom one */ \ } \ zend_hash_find(&ce->function_table, ZEND_STRS("offsetset"), (void **)&function); \ if (function->common.scope != ce) { \ pimple_object_handlers.write_dimension = pimple_object_write_dimension; \ } \ zend_hash_find(&ce->function_table, ZEND_STRS("offsetexists"), (void **)&function); \ if (function->common.scope != ce) { \ pimple_object_handlers.has_dimension = pimple_object_has_dimension; \ } \ zend_hash_find(&ce->function_table, ZEND_STRS("offsetunset"), (void **)&function); \ if (function->common.scope != ce) { \ pimple_object_handlers.unset_dimension = pimple_object_unset_dimension; \ } \ } else { \ pimple_object_handlers.read_dimension = pimple_object_read_dimension; \ pimple_object_handlers.write_dimension = pimple_object_write_dimension; \ pimple_object_handlers.has_dimension = pimple_object_has_dimension; \ pimple_object_handlers.unset_dimension = pimple_object_unset_dimension; \ }\ } while(0); #define PIMPLE_CALL_CB do { \ zend_fcall_info_argn(&fci TSRMLS_CC, 1, &object); \ fci.size = sizeof(fci); \ fci.object_ptr = retval->fcc.object_ptr; \ fci.function_name = retval->value; \ fci.no_separation = 1; \ fci.retval_ptr_ptr = &retval_ptr_ptr; \ \ zend_call_function(&fci, &retval->fcc TSRMLS_CC); \ efree(fci.params); \ if (EG(exception)) { \ return EG(uninitialized_zval_ptr); \ } \ } while(0); ZEND_BEGIN_ARG_INFO_EX(arginfo___construct, 0, 0, 0) ZEND_ARG_ARRAY_INFO(0, value, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetset, 0, 0, 2) ZEND_ARG_INFO(0, offset) ZEND_ARG_INFO(0, value) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetget, 0, 0, 1) ZEND_ARG_INFO(0, offset) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetexists, 0, 0, 1) ZEND_ARG_INFO(0, offset) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetunset, 0, 0, 1) ZEND_ARG_INFO(0, offset) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_factory, 0, 0, 1) ZEND_ARG_INFO(0, callable) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_protect, 0, 0, 1) ZEND_ARG_INFO(0, callable) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_raw, 0, 0, 1) ZEND_ARG_INFO(0, id) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_extend, 0, 0, 2) ZEND_ARG_INFO(0, id) ZEND_ARG_INFO(0, callable) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_keys, 0, 0, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_register, 0, 0, 1) ZEND_ARG_OBJ_INFO(0, provider, Pimple\\ServiceProviderInterface, 0) ZEND_ARG_ARRAY_INFO(0, values, 1) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_serviceprovider_register, 0, 0, 1) ZEND_ARG_OBJ_INFO(0, pimple, Pimple\\Container, 0) ZEND_END_ARG_INFO() static const zend_function_entry pimple_ce_functions[] = { PHP_ME(Pimple, __construct, arginfo___construct, ZEND_ACC_PUBLIC) PHP_ME(Pimple, factory, arginfo_factory, ZEND_ACC_PUBLIC) PHP_ME(Pimple, protect, arginfo_protect, ZEND_ACC_PUBLIC) PHP_ME(Pimple, raw, arginfo_raw, ZEND_ACC_PUBLIC) PHP_ME(Pimple, extend, arginfo_extend, ZEND_ACC_PUBLIC) PHP_ME(Pimple, keys, arginfo_keys, ZEND_ACC_PUBLIC) PHP_ME(Pimple, register, arginfo_register, ZEND_ACC_PUBLIC) PHP_ME(Pimple, offsetSet, arginfo_offsetset, ZEND_ACC_PUBLIC) PHP_ME(Pimple, offsetGet, arginfo_offsetget, ZEND_ACC_PUBLIC) PHP_ME(Pimple, offsetExists, arginfo_offsetexists, ZEND_ACC_PUBLIC) PHP_ME(Pimple, offsetUnset, arginfo_offsetunset, ZEND_ACC_PUBLIC) PHP_FE_END }; static const zend_function_entry pimple_serviceprovider_iface_ce_functions[] = { PHP_ABSTRACT_ME(ServiceProviderInterface, register, arginfo_serviceprovider_register) PHP_FE_END }; static void pimple_closure_free_object_storage(pimple_closure_object *obj TSRMLS_DC) { zend_object_std_dtor(&obj->zobj TSRMLS_CC); if (obj->factory) { zval_ptr_dtor(&obj->factory); } if (obj->callable) { zval_ptr_dtor(&obj->callable); } efree(obj); } static void pimple_free_object_storage(pimple_object *obj TSRMLS_DC) { zend_hash_destroy(&obj->factories); zend_hash_destroy(&obj->protected); zend_hash_destroy(&obj->values); zend_object_std_dtor(&obj->zobj TSRMLS_CC); efree(obj); } static void pimple_free_bucket(pimple_bucket_value *bucket) { if (bucket->raw) { zval_ptr_dtor(&bucket->raw); } } static zend_object_value pimple_closure_object_create(zend_class_entry *ce TSRMLS_DC) { zend_object_value retval; pimple_closure_object *pimple_closure_obj = NULL; pimple_closure_obj = ecalloc(1, sizeof(pimple_closure_object)); ZEND_OBJ_INIT(&pimple_closure_obj->zobj, ce); pimple_closure_object_handlers.get_constructor = pimple_closure_get_constructor; retval.handlers = &pimple_closure_object_handlers; retval.handle = zend_objects_store_put(pimple_closure_obj, (zend_objects_store_dtor_t) zend_objects_destroy_object, (zend_objects_free_object_storage_t) pimple_closure_free_object_storage, NULL TSRMLS_CC); return retval; } static zend_function *pimple_closure_get_constructor(zval *obj TSRMLS_DC) { zend_error(E_ERROR, "Pimple\\ContainerClosure is an internal class and cannot be instantiated"); return NULL; } static int pimple_closure_get_closure(zval *obj, zend_class_entry **ce_ptr, union _zend_function **fptr_ptr, zval **zobj_ptr TSRMLS_DC) { *zobj_ptr = obj; *ce_ptr = Z_OBJCE_P(obj); *fptr_ptr = (zend_function *)&pimple_closure_invoker_function; return SUCCESS; } static zend_object_value pimple_object_create(zend_class_entry *ce TSRMLS_DC) { zend_object_value retval; pimple_object *pimple_obj = NULL; zend_function *function = NULL; pimple_obj = emalloc(sizeof(pimple_object)); ZEND_OBJ_INIT(&pimple_obj->zobj, ce); PIMPLE_OBJECT_HANDLE_INHERITANCE_OBJECT_HANDLERS retval.handlers = &pimple_object_handlers; retval.handle = zend_objects_store_put(pimple_obj, (zend_objects_store_dtor_t) zend_objects_destroy_object, (zend_objects_free_object_storage_t) pimple_free_object_storage, NULL TSRMLS_CC); zend_hash_init(&pimple_obj->factories, PIMPLE_DEFAULT_ZVAL_CACHE_NUM, NULL, (dtor_func_t)pimple_bucket_dtor, 0); zend_hash_init(&pimple_obj->protected, PIMPLE_DEFAULT_ZVAL_CACHE_NUM, NULL, (dtor_func_t)pimple_bucket_dtor, 0); zend_hash_init(&pimple_obj->values, PIMPLE_DEFAULT_ZVAL_VALUES_NUM, NULL, (dtor_func_t)pimple_bucket_dtor, 0); return retval; } static void pimple_object_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC) { FETCH_DIM_HANDLERS_VARS pimple_bucket_value pimple_value = {0}, *found_value = NULL; ulong hash; pimple_zval_to_pimpleval(value, &pimple_value TSRMLS_CC); if (!offset) {/* $p[] = 'foo' when not overloaded */ zend_hash_next_index_insert(&pimple_obj->values, (void *)&pimple_value, sizeof(pimple_bucket_value), NULL); Z_ADDREF_P(value); return; } switch (Z_TYPE_P(offset)) { case IS_STRING: hash = zend_hash_func(Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1); zend_hash_quick_find(&pimple_obj->values, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, hash, (void **)&found_value); if (found_value && found_value->type == PIMPLE_IS_SERVICE && found_value->initialized == 1) { pimple_free_bucket(&pimple_value); zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Cannot override frozen service \"%s\".", Z_STRVAL_P(offset)); return; } if (zend_hash_quick_update(&pimple_obj->values, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, hash, (void *)&pimple_value, sizeof(pimple_bucket_value), NULL) == FAILURE) { pimple_free_bucket(&pimple_value); return; } Z_ADDREF_P(value); break; case IS_DOUBLE: case IS_BOOL: case IS_LONG: if (Z_TYPE_P(offset) == IS_DOUBLE) { index = (ulong)Z_DVAL_P(offset); } else { index = Z_LVAL_P(offset); } zend_hash_index_find(&pimple_obj->values, index, (void **)&found_value); if (found_value && found_value->type == PIMPLE_IS_SERVICE && found_value->initialized == 1) { pimple_free_bucket(&pimple_value); zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Cannot override frozen service \"%ld\".", index); return; } if (zend_hash_index_update(&pimple_obj->values, index, (void *)&pimple_value, sizeof(pimple_bucket_value), NULL) == FAILURE) { pimple_free_bucket(&pimple_value); return; } Z_ADDREF_P(value); break; case IS_NULL: /* $p[] = 'foo' when overloaded */ zend_hash_next_index_insert(&pimple_obj->values, (void *)&pimple_value, sizeof(pimple_bucket_value), NULL); Z_ADDREF_P(value); break; default: pimple_free_bucket(&pimple_value); zend_error(E_WARNING, "Unsupported offset type"); } } static void pimple_object_unset_dimension(zval *object, zval *offset TSRMLS_DC) { FETCH_DIM_HANDLERS_VARS switch (Z_TYPE_P(offset)) { case IS_STRING: zend_symtable_del(&pimple_obj->values, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1); zend_symtable_del(&pimple_obj->factories, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1); zend_symtable_del(&pimple_obj->protected, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1); break; case IS_DOUBLE: case IS_BOOL: case IS_LONG: if (Z_TYPE_P(offset) == IS_DOUBLE) { index = (ulong)Z_DVAL_P(offset); } else { index = Z_LVAL_P(offset); } zend_hash_index_del(&pimple_obj->values, index); zend_hash_index_del(&pimple_obj->factories, index); zend_hash_index_del(&pimple_obj->protected, index); break; default: zend_error(E_WARNING, "Unsupported offset type"); } } static int pimple_object_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC) { FETCH_DIM_HANDLERS_VARS pimple_bucket_value *retval = NULL; switch (Z_TYPE_P(offset)) { case IS_STRING: if (zend_symtable_find(&pimple_obj->values, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void **)&retval) == SUCCESS) { switch (check_empty) { case 0: /* isset */ return 1; /* Differs from PHP behavior (Z_TYPE_P(retval->value) != IS_NULL;) */ case 1: /* empty */ default: return zend_is_true(retval->value); } } return 0; break; case IS_DOUBLE: case IS_BOOL: case IS_LONG: if (Z_TYPE_P(offset) == IS_DOUBLE) { index = (ulong)Z_DVAL_P(offset); } else { index = Z_LVAL_P(offset); } if (zend_hash_index_find(&pimple_obj->values, index, (void **)&retval) == SUCCESS) { switch (check_empty) { case 0: /* isset */ return 1; /* Differs from PHP behavior (Z_TYPE_P(retval->value) != IS_NULL;)*/ case 1: /* empty */ default: return zend_is_true(retval->value); } } return 0; break; default: zend_error(E_WARNING, "Unsupported offset type"); return 0; } } static zval *pimple_object_read_dimension(zval *object, zval *offset, int type TSRMLS_DC) { FETCH_DIM_HANDLERS_VARS pimple_bucket_value *retval = NULL; zend_fcall_info fci = {0}; zval *retval_ptr_ptr = NULL; switch (Z_TYPE_P(offset)) { case IS_STRING: if (zend_symtable_find(&pimple_obj->values, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void **)&retval) == FAILURE) { zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Identifier \"%s\" is not defined.", Z_STRVAL_P(offset)); return EG(uninitialized_zval_ptr); } break; case IS_DOUBLE: case IS_BOOL: case IS_LONG: if (Z_TYPE_P(offset) == IS_DOUBLE) { index = (ulong)Z_DVAL_P(offset); } else { index = Z_LVAL_P(offset); } if (zend_hash_index_find(&pimple_obj->values, index, (void **)&retval) == FAILURE) { return EG(uninitialized_zval_ptr); } break; case IS_NULL: /* $p[][3] = 'foo' first dim access */ return EG(uninitialized_zval_ptr); break; default: zend_error(E_WARNING, "Unsupported offset type"); return EG(uninitialized_zval_ptr); } if(retval->type == PIMPLE_IS_PARAM) { return retval->value; } if (zend_hash_index_exists(&pimple_obj->protected, retval->handle_num)) { /* Service is protected, return the value every time */ return retval->value; } if (zend_hash_index_exists(&pimple_obj->factories, retval->handle_num)) { /* Service is a factory, call it everytime and never cache its result */ PIMPLE_CALL_CB Z_DELREF_P(retval_ptr_ptr); /* fetch dim addr will increment refcount */ return retval_ptr_ptr; } if (retval->initialized == 1) { /* Service has already been called, return its cached value */ return retval->value; } ALLOC_INIT_ZVAL(retval->raw); MAKE_COPY_ZVAL(&retval->value, retval->raw); PIMPLE_CALL_CB retval->initialized = 1; zval_ptr_dtor(&retval->value); retval->value = retval_ptr_ptr; return retval->value; } static int pimple_zval_is_valid_callback(zval *_zval, pimple_bucket_value *_pimple_bucket_value TSRMLS_DC) { if (Z_TYPE_P(_zval) != IS_OBJECT) { return FAILURE; } if (_pimple_bucket_value->fcc.called_scope) { return SUCCESS; } if (Z_OBJ_HANDLER_P(_zval, get_closure) && Z_OBJ_HANDLER_P(_zval, get_closure)(_zval, &_pimple_bucket_value->fcc.calling_scope, &_pimple_bucket_value->fcc.function_handler, &_pimple_bucket_value->fcc.object_ptr TSRMLS_CC) == SUCCESS) { _pimple_bucket_value->fcc.called_scope = _pimple_bucket_value->fcc.calling_scope; return SUCCESS; } else { return FAILURE; } } static int pimple_zval_to_pimpleval(zval *_zval, pimple_bucket_value *_pimple_bucket_value TSRMLS_DC) { _pimple_bucket_value->value = _zval; if (Z_TYPE_P(_zval) != IS_OBJECT) { return PIMPLE_IS_PARAM; } if (pimple_zval_is_valid_callback(_zval, _pimple_bucket_value TSRMLS_CC) == SUCCESS) { _pimple_bucket_value->type = PIMPLE_IS_SERVICE; _pimple_bucket_value->handle_num = Z_OBJ_HANDLE_P(_zval); } return PIMPLE_IS_SERVICE; } static void pimple_bucket_dtor(pimple_bucket_value *bucket) { zval_ptr_dtor(&bucket->value); pimple_free_bucket(bucket); } PHP_METHOD(Pimple, protect) { zval *protected = NULL; pimple_object *pobj = NULL; pimple_bucket_value bucket = {0}; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &protected) == FAILURE) { return; } if (pimple_zval_is_valid_callback(protected, &bucket TSRMLS_CC) == FAILURE) { pimple_free_bucket(&bucket); zend_throw_exception(spl_ce_InvalidArgumentException, "Callable is not a Closure or invokable object.", 0 TSRMLS_CC); return; } pimple_zval_to_pimpleval(protected, &bucket TSRMLS_CC); pobj = (pimple_object *)zend_object_store_get_object(getThis() TSRMLS_CC); if (zend_hash_index_update(&pobj->protected, bucket.handle_num, (void *)&bucket, sizeof(pimple_bucket_value), NULL) == SUCCESS) { Z_ADDREF_P(protected); RETURN_ZVAL(protected, 1 , 0); } else { pimple_free_bucket(&bucket); } RETURN_FALSE; } PHP_METHOD(Pimple, raw) { zval *offset = NULL; pimple_object *pobj = NULL; pimple_bucket_value *value = NULL; ulong index; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &offset) == FAILURE) { return; } pobj = zend_object_store_get_object(getThis() TSRMLS_CC); switch (Z_TYPE_P(offset)) { case IS_STRING: if (zend_symtable_find(&pobj->values, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void *)&value) == FAILURE) { zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Identifier \"%s\" is not defined.", Z_STRVAL_P(offset)); RETURN_NULL(); } break; case IS_DOUBLE: case IS_BOOL: case IS_LONG: if (Z_TYPE_P(offset) == IS_DOUBLE) { index = (ulong)Z_DVAL_P(offset); } else { index = Z_LVAL_P(offset); } if (zend_hash_index_find(&pobj->values, index, (void *)&value) == FAILURE) { RETURN_NULL(); } break; case IS_NULL: default: zend_error(E_WARNING, "Unsupported offset type"); } if (value->raw) { RETVAL_ZVAL(value->raw, 1, 0); } else { RETVAL_ZVAL(value->value, 1, 0); } } PHP_METHOD(Pimple, extend) { zval *offset = NULL, *callable = NULL, *pimple_closure_obj = NULL; pimple_bucket_value bucket = {0}, *value = NULL; pimple_object *pobj = NULL; pimple_closure_object *pcobj = NULL; ulong index; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &offset, &callable) == FAILURE) { return; } pobj = zend_object_store_get_object(getThis() TSRMLS_CC); switch (Z_TYPE_P(offset)) { case IS_STRING: if (zend_symtable_find(&pobj->values, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void *)&value) == FAILURE) { zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Identifier \"%s\" is not defined.", Z_STRVAL_P(offset)); RETURN_NULL(); } if (value->type != PIMPLE_IS_SERVICE) { zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Identifier \"%s\" does not contain an object definition.", Z_STRVAL_P(offset)); RETURN_NULL(); } break; case IS_DOUBLE: case IS_BOOL: case IS_LONG: if (Z_TYPE_P(offset) == IS_DOUBLE) { index = (ulong)Z_DVAL_P(offset); } else { index = Z_LVAL_P(offset); } if (zend_hash_index_find(&pobj->values, index, (void *)&value) == FAILURE) { zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Identifier \"%ld\" is not defined.", index); RETURN_NULL(); } if (value->type != PIMPLE_IS_SERVICE) { zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Identifier \"%ld\" does not contain an object definition.", index); RETURN_NULL(); } break; case IS_NULL: default: zend_error(E_WARNING, "Unsupported offset type"); } if (pimple_zval_is_valid_callback(callable, &bucket TSRMLS_CC) == FAILURE) { pimple_free_bucket(&bucket); zend_throw_exception(spl_ce_InvalidArgumentException, "Extension service definition is not a Closure or invokable object.", 0 TSRMLS_CC); RETURN_NULL(); } pimple_free_bucket(&bucket); ALLOC_INIT_ZVAL(pimple_closure_obj); object_init_ex(pimple_closure_obj, pimple_closure_ce); pcobj = zend_object_store_get_object(pimple_closure_obj TSRMLS_CC); pcobj->callable = callable; pcobj->factory = value->value; Z_ADDREF_P(callable); Z_ADDREF_P(value->value); if (zend_hash_index_exists(&pobj->factories, value->handle_num)) { pimple_zval_to_pimpleval(pimple_closure_obj, &bucket TSRMLS_CC); zend_hash_index_del(&pobj->factories, value->handle_num); zend_hash_index_update(&pobj->factories, bucket.handle_num, (void *)&bucket, sizeof(pimple_bucket_value), NULL); Z_ADDREF_P(pimple_closure_obj); } pimple_object_write_dimension(getThis(), offset, pimple_closure_obj TSRMLS_CC); RETVAL_ZVAL(pimple_closure_obj, 1, 1); } PHP_METHOD(Pimple, keys) { HashPosition pos; pimple_object *pobj = NULL; zval **value = NULL; zval *endval = NULL; char *str_index = NULL; int str_len; ulong num_index; if (zend_parse_parameters_none() == FAILURE) { return; } pobj = zend_object_store_get_object(getThis() TSRMLS_CC); array_init_size(return_value, zend_hash_num_elements(&pobj->values)); zend_hash_internal_pointer_reset_ex(&pobj->values, &pos); while(zend_hash_get_current_data_ex(&pobj->values, (void **)&value, &pos) == SUCCESS) { MAKE_STD_ZVAL(endval); switch (zend_hash_get_current_key_ex(&pobj->values, &str_index, (uint *)&str_len, &num_index, 0, &pos)) { case HASH_KEY_IS_STRING: ZVAL_STRINGL(endval, str_index, str_len - 1, 1); zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &endval, sizeof(zval *), NULL); break; case HASH_KEY_IS_LONG: ZVAL_LONG(endval, num_index); zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &endval, sizeof(zval *), NULL); break; } zend_hash_move_forward_ex(&pobj->values, &pos); } } PHP_METHOD(Pimple, factory) { zval *factory = NULL; pimple_object *pobj = NULL; pimple_bucket_value bucket = {0}; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &factory) == FAILURE) { return; } if (pimple_zval_is_valid_callback(factory, &bucket TSRMLS_CC) == FAILURE) { pimple_free_bucket(&bucket); zend_throw_exception(spl_ce_InvalidArgumentException, "Service definition is not a Closure or invokable object.", 0 TSRMLS_CC); return; } pimple_zval_to_pimpleval(factory, &bucket TSRMLS_CC); pobj = (pimple_object *)zend_object_store_get_object(getThis() TSRMLS_CC); if (zend_hash_index_update(&pobj->factories, bucket.handle_num, (void *)&bucket, sizeof(pimple_bucket_value), NULL) == SUCCESS) { Z_ADDREF_P(factory); RETURN_ZVAL(factory, 1 , 0); } else { pimple_free_bucket(&bucket); } RETURN_FALSE; } PHP_METHOD(Pimple, offsetSet) { zval *offset = NULL, *value = NULL; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &offset, &value) == FAILURE) { return; } pimple_object_write_dimension(getThis(), offset, value TSRMLS_CC); } PHP_METHOD(Pimple, offsetGet) { zval *offset = NULL, *retval = NULL; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &offset) == FAILURE) { return; } retval = pimple_object_read_dimension(getThis(), offset, 0 TSRMLS_CC); RETVAL_ZVAL(retval, 1, 0); } PHP_METHOD(Pimple, offsetUnset) { zval *offset = NULL; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &offset) == FAILURE) { return; } pimple_object_unset_dimension(getThis(), offset TSRMLS_CC); } PHP_METHOD(Pimple, offsetExists) { zval *offset = NULL; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &offset) == FAILURE) { return; } RETVAL_BOOL(pimple_object_has_dimension(getThis(), offset, 1 TSRMLS_CC)); } PHP_METHOD(Pimple, register) { zval *provider; zval **data; zval *retval = NULL; zval key; HashTable *array = NULL; HashPosition pos; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|h", &provider, pimple_serviceprovider_ce, &array) == FAILURE) { return; } RETVAL_ZVAL(getThis(), 1, 0); zend_call_method_with_1_params(&provider, Z_OBJCE_P(provider), NULL, "register", &retval, getThis()); if (retval) { zval_ptr_dtor(&retval); } if (!array) { return; } zend_hash_internal_pointer_reset_ex(array, &pos); while(zend_hash_get_current_data_ex(array, (void **)&data, &pos) == SUCCESS) { zend_hash_get_current_key_zval_ex(array, &key, &pos); pimple_object_write_dimension(getThis(), &key, *data TSRMLS_CC); zend_hash_move_forward_ex(array, &pos); } } PHP_METHOD(Pimple, __construct) { zval *values = NULL, **pData = NULL, offset; HashPosition pos; char *str_index = NULL; zend_uint str_length; ulong num_index; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!", &values) == FAILURE || !values) { return; } zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(values), &pos); while (zend_hash_has_more_elements_ex(Z_ARRVAL_P(values), &pos) == SUCCESS) { zend_hash_get_current_data_ex(Z_ARRVAL_P(values), (void **)&pData, &pos); zend_hash_get_current_key_ex(Z_ARRVAL_P(values), &str_index, &str_length, &num_index, 0, &pos); INIT_ZVAL(offset); if (zend_hash_get_current_key_type_ex(Z_ARRVAL_P(values), &pos) == HASH_KEY_IS_LONG) { ZVAL_LONG(&offset, num_index); } else { ZVAL_STRINGL(&offset, str_index, (str_length - 1), 0); } pimple_object_write_dimension(getThis(), &offset, *pData TSRMLS_CC); zend_hash_move_forward_ex(Z_ARRVAL_P(values), &pos); } } /* * This is PHP code snippet handling extend()s calls : $extended = function ($c) use ($callable, $factory) { return $callable($factory($c), $c); }; */ PHP_METHOD(PimpleClosure, invoker) { pimple_closure_object *pcobj = NULL; zval *arg = NULL, *retval = NULL, *newretval = NULL; zend_fcall_info fci = {0}; zval **args[2]; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &arg) == FAILURE) { return; } pcobj = zend_object_store_get_object(getThis() TSRMLS_CC); fci.function_name = pcobj->factory; args[0] = &arg; zend_fcall_info_argp(&fci TSRMLS_CC, 1, args); fci.retval_ptr_ptr = &retval; fci.size = sizeof(fci); if (zend_call_function(&fci, NULL TSRMLS_CC) == FAILURE || EG(exception)) { efree(fci.params); return; /* Should here return default zval */ } efree(fci.params); memset(&fci, 0, sizeof(fci)); fci.size = sizeof(fci); fci.function_name = pcobj->callable; args[0] = &retval; args[1] = &arg; zend_fcall_info_argp(&fci TSRMLS_CC, 2, args); fci.retval_ptr_ptr = &newretval; if (zend_call_function(&fci, NULL TSRMLS_CC) == FAILURE || EG(exception)) { efree(fci.params); zval_ptr_dtor(&retval); return; } efree(fci.params); zval_ptr_dtor(&retval); RETVAL_ZVAL(newretval, 1 ,1); } PHP_MINIT_FUNCTION(pimple) { zend_class_entry tmp_pimple_ce, tmp_pimple_closure_ce, tmp_pimple_serviceprovider_iface_ce; INIT_NS_CLASS_ENTRY(tmp_pimple_ce, PIMPLE_NS, "Container", pimple_ce_functions); INIT_NS_CLASS_ENTRY(tmp_pimple_closure_ce, PIMPLE_NS, "ContainerClosure", NULL); INIT_NS_CLASS_ENTRY(tmp_pimple_serviceprovider_iface_ce, PIMPLE_NS, "ServiceProviderInterface", pimple_serviceprovider_iface_ce_functions); tmp_pimple_ce.create_object = pimple_object_create; tmp_pimple_closure_ce.create_object = pimple_closure_object_create; pimple_ce = zend_register_internal_class(&tmp_pimple_ce TSRMLS_CC); zend_class_implements(pimple_ce TSRMLS_CC, 1, zend_ce_arrayaccess); pimple_closure_ce = zend_register_internal_class(&tmp_pimple_closure_ce TSRMLS_CC); pimple_closure_ce->ce_flags |= ZEND_ACC_FINAL_CLASS; pimple_serviceprovider_ce = zend_register_internal_interface(&tmp_pimple_serviceprovider_iface_ce TSRMLS_CC); memcpy(&pimple_closure_object_handlers, zend_get_std_object_handlers(), sizeof(*zend_get_std_object_handlers())); pimple_object_handlers = std_object_handlers; pimple_closure_object_handlers.get_closure = pimple_closure_get_closure; pimple_closure_invoker_function.function_name = "Pimple closure internal invoker"; pimple_closure_invoker_function.fn_flags |= ZEND_ACC_CLOSURE; pimple_closure_invoker_function.handler = ZEND_MN(PimpleClosure_invoker); pimple_closure_invoker_function.num_args = 1; pimple_closure_invoker_function.required_num_args = 1; pimple_closure_invoker_function.scope = pimple_closure_ce; pimple_closure_invoker_function.type = ZEND_INTERNAL_FUNCTION; pimple_closure_invoker_function.module = &pimple_module_entry; return SUCCESS; } PHP_MINFO_FUNCTION(pimple) { php_info_print_table_start(); php_info_print_table_header(2, "SensioLabs Pimple C support", "enabled"); php_info_print_table_row(2, "Pimple supported version", PIMPLE_VERSION); php_info_print_table_end(); php_info_print_box_start(0); php_write((void *)ZEND_STRL("SensioLabs Pimple C support developed by Julien Pauli") TSRMLS_CC); if (!sapi_module.phpinfo_as_text) { php_write((void *)ZEND_STRL(sensiolabs_logo) TSRMLS_CC); } php_info_print_box_end(); } zend_module_entry pimple_module_entry = { STANDARD_MODULE_HEADER, "pimple", NULL, PHP_MINIT(pimple), NULL, NULL, NULL, PHP_MINFO(pimple), PIMPLE_VERSION, STANDARD_MODULE_PROPERTIES }; #ifdef COMPILE_DL_PIMPLE ZEND_GET_MODULE(pimple) #endif