pax_global_header00006660000000000000000000000064125745673530014533gustar00rootroot0000000000000052 comment=a30f7d6e57565a2e1a316e1baf2a483f788b258a Pimple-3.0.2/000077500000000000000000000000001257456735300127635ustar00rootroot00000000000000Pimple-3.0.2/.gitignore000066400000000000000000000000431257456735300147500ustar00rootroot00000000000000phpunit.xml composer.lock /vendor/ Pimple-3.0.2/.travis.yml000066400000000000000000000013451257456735300150770ustar00rootroot00000000000000language: php env: matrix: - PIMPLE_EXT=no - PIMPLE_EXT=yes global: - REPORT_EXIT_STATUS=1 php: - 5.3 - 5.4 - 5.5 - 5.6 - hhvm before_script: - composer self-update - COMPOSER_ROOT_VERSION=dev-master composer dump-autoload - if [ "$PIMPLE_EXT" == "yes" ]; then sh -c "cd ext/pimple && phpize && ./configure && make && sudo make install"; fi - if [ "$PIMPLE_EXT" == "yes" ]; then echo "extension=pimple.so" >> `php --ini | grep "Loaded Configuration" | sed -e "s|.*:\s*||"`; fi script: - cd ext/pimple - if [ "$PIMPLE_EXT" == "yes" ]; then yes n | make test | tee output ; grep -E 'Tests failed +. +0' output; fi - cd ../.. - phpunit matrix: exclude: - php: hhvm env: PIMPLE_EXT=yes Pimple-3.0.2/CHANGELOG000066400000000000000000000016011257456735300141730ustar00rootroot00000000000000* 3.0.2 (2015-09-11) * refactored the C extension * minor non-significant changes * 3.0.1 (2015-07-30) * simplified some code * fixed a segfault in the C extension * 3.0.0 (2014-07-24) * removed the Pimple class alias (use Pimple\Container instead) * 2.1.1 (2014-07-24) * fixed compiler warnings for the C extension * fixed code when dealing with circular references * 2.1.0 (2014-06-24) * moved the Pimple to Pimple\Container (with a BC layer -- Pimple is now a deprecated alias which will be removed in Pimple 3.0) * added Pimple\ServiceProviderInterface (and Pimple::register()) * 2.0.0 (2014-02-10) * changed extend to automatically re-assign the extended service and keep it as shared or factory (to keep BC, extend still returns the extended service) * changed services to be shared by default (use factory() for factory services) * 1.0.0 * initial version Pimple-3.0.2/LICENSE000066400000000000000000000020511257456735300137660ustar00rootroot00000000000000Copyright (c) 2009-2015 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. Pimple-3.0.2/README.rst000066400000000000000000000127051257456735300144570ustar00rootroot00000000000000Pimple ====== .. caution:: This is the documentation for Pimple 3.x. If you are using Pimple 1.x, read the `Pimple 1.x documentation`_. Reading the Pimple 1.x code is also a good way to learn more about how to create a simple Dependency Injection Container (recent versions of Pimple are more focused on performance). Pimple is a small Dependency Injection Container for PHP. Installation ------------ Before using Pimple in your project, add it to your ``composer.json`` file: .. code-block:: bash $ ./composer.phar require pimple/pimple ~3.0 Alternatively, Pimple is also available as a PHP C extension: .. code-block:: bash $ git clone https://github.com/silexphp/Pimple $ cd Pimple/ext/pimple $ phpize $ ./configure $ make $ make install Usage ----- Creating a container is a matter of creating a ``Container`` instance: .. code-block:: php use Pimple\Container; $container = new Container(); As many other dependency injection containers, Pimple manages two different kind of data: **services** and **parameters**. Defining Services ~~~~~~~~~~~~~~~~~ A service is an object that does something as part of a larger system. Examples of services: a database connection, a templating engine, or a mailer. Almost any **global** object can be a service. Services are defined by **anonymous functions** that return an instance of an object: .. code-block:: php // define some services $container['session_storage'] = function ($c) { return new SessionStorage('SESSION_ID'); }; $container['session'] = function ($c) { return new Session($c['session_storage']); }; Notice that the anonymous function has access to the current container instance, allowing references to other services or parameters. As objects are only created when you get them, the order of the definitions does not matter. Using the defined services is also very easy: .. code-block:: php // get the session object $session = $container['session']; // the above call is roughly equivalent to the following code: // $storage = new SessionStorage('SESSION_ID'); // $session = new Session($storage); Defining Factory Services ~~~~~~~~~~~~~~~~~~~~~~~~~ By default, each time you get a service, Pimple returns the **same instance** of it. If you want a different instance to be returned for all calls, wrap your anonymous function with the ``factory()`` method .. code-block:: php $container['session'] = $container->factory(function ($c) { return new Session($c['session_storage']); }); Now, each call to ``$container['session']`` returns a new instance of the session. Defining Parameters ~~~~~~~~~~~~~~~~~~~ Defining a parameter allows to ease the configuration of your container from the outside and to store global values: .. code-block:: php // define some parameters $container['cookie_name'] = 'SESSION_ID'; $container['session_storage_class'] = 'SessionStorage'; If you change the ``session_storage`` service definition like below: .. code-block:: php $container['session_storage'] = function ($c) { return new $c['session_storage_class']($c['cookie_name']); }; You can now easily change the cookie name by overriding the ``session_storage_class`` parameter instead of redefining the service definition. Protecting Parameters ~~~~~~~~~~~~~~~~~~~~~ Because Pimple sees anonymous functions as service definitions, you need to wrap anonymous functions with the ``protect()`` method to store them as parameters: .. code-block:: php $container['random_func'] = $container->protect(function () { return rand(); }); Modifying Services after Definition ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In some cases you may want to modify a service definition after it has been defined. You can use the ``extend()`` method to define additional code to be run on your service just after it is created: .. code-block:: php $container['session_storage'] = function ($c) { return new $c['session_storage_class']($c['cookie_name']); }; $container->extend('session_storage', function ($storage, $c) { $storage->...(); return $storage; }); The first argument is the name of the service to extend, the second a function that gets access to the object instance and the container. Extending a Container ~~~~~~~~~~~~~~~~~~~~~ If you use the same libraries over and over, you might want to reuse some services from one project to the next one; package your services into a **provider** by implementing ``Pimple\ServiceProviderInterface``: .. code-block:: php use Pimple\Container; class FooProvider implements Pimple\ServiceProviderInterface { public function register(Container $pimple) { // register some services and parameters // on $pimple } } Then, register the provider on a Container: .. code-block:: php $pimple->register(new FooProvider()); Fetching the Service Creation Function ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ When you access an object, Pimple automatically calls the anonymous function that you defined, which creates the service object for you. If you want to get raw access to this function, you can use the ``raw()`` method: .. code-block:: php $container['session'] = function ($c) { return new Session($c['session_storage']); }; $sessionFunction = $container->raw('session'); .. _Pimple 1.x documentation: https://github.com/silexphp/Pimple/tree/1.1 Pimple-3.0.2/composer.json000066400000000000000000000011101257456735300154760ustar00rootroot00000000000000{ "name": "pimple/pimple", "type": "library", "description": "Pimple, a simple Dependency Injection Container", "keywords": ["dependency injection", "container"], "homepage": "http://pimple.sensiolabs.org", "license": "MIT", "authors": [ { "name": "Fabien Potencier", "email": "fabien@symfony.com" } ], "require": { "php": ">=5.3.0" }, "autoload": { "psr-0": { "Pimple": "src/" } }, "extra": { "branch-alias": { "dev-master": "3.0.x-dev" } } } Pimple-3.0.2/ext/000077500000000000000000000000001257456735300135635ustar00rootroot00000000000000Pimple-3.0.2/ext/pimple/000077500000000000000000000000001257456735300150515ustar00rootroot00000000000000Pimple-3.0.2/ext/pimple/.gitignore000066400000000000000000000004771257456735300170510ustar00rootroot00000000000000*.sw* .deps Makefile Makefile.fragments Makefile.global Makefile.objects acinclude.m4 aclocal.m4 build/ config.cache config.guess config.h config.h.in config.log config.nice config.status config.sub configure configure.in install-sh libtool ltmain.sh missing mkinstalldirs run-tests.php *.loT .libs/ modules/ *.la *.lo Pimple-3.0.2/ext/pimple/README.md000066400000000000000000000002461257456735300163320ustar00rootroot00000000000000This is Pimple 2 implemented in C * PHP >= 5.3 * Not tested under Windows, might work Install ======= > phpize > ./configure > make > make install Pimple-3.0.2/ext/pimple/config.m4000066400000000000000000000037521257456735300165670ustar00rootroot00000000000000dnl $Id$ dnl config.m4 for extension pimple dnl Comments in this file start with the string 'dnl'. dnl Remove where necessary. This file will not work dnl without editing. dnl If your extension references something external, use with: dnl PHP_ARG_WITH(pimple, for pimple support, dnl Make sure that the comment is aligned: dnl [ --with-pimple Include pimple support]) dnl Otherwise use enable: PHP_ARG_ENABLE(pimple, whether to enable pimple support, dnl Make sure that the comment is aligned: [ --enable-pimple Enable pimple support]) if test "$PHP_PIMPLE" != "no"; then dnl Write more examples of tests here... dnl # --with-pimple -> check with-path dnl SEARCH_PATH="/usr/local /usr" # you might want to change this dnl SEARCH_FOR="/include/pimple.h" # you most likely want to change this dnl if test -r $PHP_PIMPLE/$SEARCH_FOR; then # path given as parameter dnl PIMPLE_DIR=$PHP_PIMPLE dnl else # search default path list dnl AC_MSG_CHECKING([for pimple files in default path]) dnl for i in $SEARCH_PATH ; do dnl if test -r $i/$SEARCH_FOR; then dnl PIMPLE_DIR=$i dnl AC_MSG_RESULT(found in $i) dnl fi dnl done dnl fi dnl dnl if test -z "$PIMPLE_DIR"; then dnl AC_MSG_RESULT([not found]) dnl AC_MSG_ERROR([Please reinstall the pimple distribution]) dnl fi dnl # --with-pimple -> add include path dnl PHP_ADD_INCLUDE($PIMPLE_DIR/include) dnl # --with-pimple -> check for lib and symbol presence dnl LIBNAME=pimple # you may want to change this dnl LIBSYMBOL=pimple # you most likely want to change this dnl PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL, dnl [ dnl PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $PIMPLE_DIR/lib, PIMPLE_SHARED_LIBADD) dnl AC_DEFINE(HAVE_PIMPLELIB,1,[ ]) dnl ],[ dnl AC_MSG_ERROR([wrong pimple lib version or lib not found]) dnl ],[ dnl -L$PIMPLE_DIR/lib -lm dnl ]) dnl dnl PHP_SUBST(PIMPLE_SHARED_LIBADD) PHP_NEW_EXTENSION(pimple, pimple.c, $ext_shared) fi Pimple-3.0.2/ext/pimple/config.w32000066400000000000000000000004501257456735300166520ustar00rootroot00000000000000// $Id$ // vim:ft=javascript // If your extension references something external, use ARG_WITH // ARG_WITH("pimple", "for pimple support", "no"); // Otherwise, use ARG_ENABLE // ARG_ENABLE("pimple", "enable pimple support", "no"); if (PHP_PIMPLE != "no") { EXTENSION("pimple", "pimple.c"); } Pimple-3.0.2/ext/pimple/php_pimple.h000066400000000000000000000130661257456735300173650ustar00rootroot00000000000000 /* * 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. */ #ifndef PHP_PIMPLE_H #define PHP_PIMPLE_H extern zend_module_entry pimple_module_entry; #define phpext_pimple_ptr &pimple_module_entry #ifdef PHP_WIN32 # define PHP_PIMPLE_API __declspec(dllexport) #elif defined(__GNUC__) && __GNUC__ >= 4 # define PHP_PIMPLE_API __attribute__ ((visibility("default"))) #else # define PHP_PIMPLE_API #endif #ifdef ZTS #include "TSRM.h" #endif #define PIMPLE_VERSION "3.0.2" #define PIMPLE_NS "Pimple" #define PIMPLE_DEFAULT_ZVAL_CACHE_NUM 5 #define PIMPLE_DEFAULT_ZVAL_VALUES_NUM 10 zend_module_entry *get_module(void); PHP_MINIT_FUNCTION(pimple); PHP_MINFO_FUNCTION(pimple); PHP_METHOD(Pimple, __construct); PHP_METHOD(Pimple, factory); PHP_METHOD(Pimple, protect); PHP_METHOD(Pimple, raw); PHP_METHOD(Pimple, extend); PHP_METHOD(Pimple, keys); PHP_METHOD(Pimple, register); PHP_METHOD(Pimple, offsetSet); PHP_METHOD(Pimple, offsetUnset); PHP_METHOD(Pimple, offsetGet); PHP_METHOD(Pimple, offsetExists); PHP_METHOD(PimpleClosure, invoker); typedef struct _pimple_bucket_value { zval *value; /* Must be the first element */ zval *raw; zend_object_handle handle_num; enum { PIMPLE_IS_PARAM = 0, PIMPLE_IS_SERVICE = 2 } type; zend_bool initialized; zend_fcall_info_cache fcc; } pimple_bucket_value; typedef struct _pimple_object { zend_object zobj; HashTable values; HashTable factories; HashTable protected; } pimple_object; typedef struct _pimple_closure_object { zend_object zobj; zval *callable; zval *factory; } pimple_closure_object; static const char sensiolabs_logo[] = ""; static int pimple_zval_to_pimpleval(zval *_zval, pimple_bucket_value *_pimple_bucket_value TSRMLS_DC); static int pimple_zval_is_valid_callback(zval *_zval, pimple_bucket_value *_pimple_bucket_value TSRMLS_DC); static void pimple_bucket_dtor(pimple_bucket_value *bucket); static void pimple_free_bucket(pimple_bucket_value *bucket); static zval *pimple_object_read_dimension(zval *object, zval *offset, int type TSRMLS_DC); static void pimple_object_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC); static int pimple_object_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC); static void pimple_object_unset_dimension(zval *object, zval *offset TSRMLS_DC); static zend_object_value pimple_object_create(zend_class_entry *ce TSRMLS_DC); static void pimple_free_object_storage(pimple_object *obj TSRMLS_DC); static void pimple_closure_free_object_storage(pimple_closure_object *obj TSRMLS_DC); static zend_object_value pimple_closure_object_create(zend_class_entry *ce TSRMLS_DC); static zend_function *pimple_closure_get_constructor(zval * TSRMLS_DC); static int pimple_closure_get_closure(zval *obj, zend_class_entry **ce_ptr, union _zend_function **fptr_ptr, zval **zobj_ptr TSRMLS_DC); #ifdef ZTS #define PIMPLE_G(v) TSRMG(pimple_globals_id, zend_pimple_globals *, v) #else #define PIMPLE_G(v) (pimple_globals.v) #endif #endif /* PHP_PIMPLE_H */ Pimple-3.0.2/ext/pimple/pimple.c000066400000000000000000000710571257456735300165150ustar00rootroot00000000000000 /* * 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 Pimple-3.0.2/ext/pimple/pimple_compat.h000066400000000000000000000055471257456735300200660ustar00rootroot00000000000000 /* * 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. */ #ifndef PIMPLE_COMPAT_H_ #define PIMPLE_COMPAT_H_ #include "Zend/zend_extensions.h" /* for ZEND_EXTENSION_API_NO */ #define PHP_5_0_X_API_NO 220040412 #define PHP_5_1_X_API_NO 220051025 #define PHP_5_2_X_API_NO 220060519 #define PHP_5_3_X_API_NO 220090626 #define PHP_5_4_X_API_NO 220100525 #define PHP_5_5_X_API_NO 220121212 #define PHP_5_6_X_API_NO 220131226 #define IS_PHP_56 ZEND_EXTENSION_API_NO == PHP_5_6_X_API_NO #define IS_AT_LEAST_PHP_56 ZEND_EXTENSION_API_NO >= PHP_5_6_X_API_NO #define IS_PHP_55 ZEND_EXTENSION_API_NO == PHP_5_5_X_API_NO #define IS_AT_LEAST_PHP_55 ZEND_EXTENSION_API_NO >= PHP_5_5_X_API_NO #define IS_PHP_54 ZEND_EXTENSION_API_NO == PHP_5_4_X_API_NO #define IS_AT_LEAST_PHP_54 ZEND_EXTENSION_API_NO >= PHP_5_4_X_API_NO #define IS_PHP_53 ZEND_EXTENSION_API_NO == PHP_5_3_X_API_NO #define IS_AT_LEAST_PHP_53 ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO #if IS_PHP_53 #define object_properties_init(obj, ce) do { \ zend_hash_copy(obj->properties, &ce->default_properties, zval_copy_property_ctor(ce), NULL, sizeof(zval *)); \ } while (0); #endif #define ZEND_OBJ_INIT(obj, ce) do { \ zend_object_std_init(obj, ce TSRMLS_CC); \ object_properties_init((obj), (ce)); \ } while(0); #if IS_PHP_53 || IS_PHP_54 static void zend_hash_get_current_key_zval_ex(const HashTable *ht, zval *key, HashPosition *pos) { Bucket *p; p = pos ? (*pos) : ht->pInternalPointer; if (!p) { Z_TYPE_P(key) = IS_NULL; } else if (p->nKeyLength) { Z_TYPE_P(key) = IS_STRING; Z_STRVAL_P(key) = estrndup(p->arKey, p->nKeyLength - 1); Z_STRLEN_P(key) = p->nKeyLength - 1; } else { Z_TYPE_P(key) = IS_LONG; Z_LVAL_P(key) = p->h; } } #endif #endif /* PIMPLE_COMPAT_H_ */ Pimple-3.0.2/ext/pimple/tests/000077500000000000000000000000001257456735300162135ustar00rootroot00000000000000Pimple-3.0.2/ext/pimple/tests/001.phpt000066400000000000000000000011261257456735300174100ustar00rootroot00000000000000--TEST-- Test for read_dim/write_dim handlers --SKIPIF-- --FILE-- --EXPECTF-- foo 42 foo2 foo99 baz strstrPimple-3.0.2/ext/pimple/tests/002.phpt000066400000000000000000000004031257456735300174060ustar00rootroot00000000000000--TEST-- Test for constructor --SKIPIF-- --FILE-- 'foo')); var_dump($p[42]); ?> --EXPECT-- NULL string(3) "foo" Pimple-3.0.2/ext/pimple/tests/003.phpt000066400000000000000000000004001257456735300174040ustar00rootroot00000000000000--TEST-- Test empty dimensions --SKIPIF-- --FILE-- --EXPECT-- int(42) string(3) "bar"Pimple-3.0.2/ext/pimple/tests/004.phpt000066400000000000000000000010411257456735300174070ustar00rootroot00000000000000--TEST-- Test has/unset dim handlers --SKIPIF-- --FILE-- --EXPECT-- int(42) NULL bool(true) bool(false) bool(true) bool(true)Pimple-3.0.2/ext/pimple/tests/005.phpt000066400000000000000000000006531257456735300174200ustar00rootroot00000000000000--TEST-- Test simple class inheritance --SKIPIF-- --FILE-- someAttr; ?> --EXPECT-- string(3) "hit" foo fooAttrPimple-3.0.2/ext/pimple/tests/006.phpt000066400000000000000000000021251257456735300174150ustar00rootroot00000000000000--TEST-- Test complex class inheritance --SKIPIF-- --FILE-- 'bar', 88 => 'baz'); $p = new TestPimple($defaultValues); $p[42] = 'foo'; var_dump($p[42]); var_dump($p[0]); ?> --EXPECT-- string(13) "hit offsetset" string(27) "hit offsetget in TestPimple" string(25) "hit offsetget in MyPimple" string(3) "foo" string(27) "hit offsetget in TestPimple" string(25) "hit offsetget in MyPimple" string(3) "baz"Pimple-3.0.2/ext/pimple/tests/007.phpt000066400000000000000000000005621257456735300174210ustar00rootroot00000000000000--TEST-- Test for read_dim/write_dim handlers --SKIPIF-- --FILE-- --EXPECTF-- foo 42Pimple-3.0.2/ext/pimple/tests/008.phpt000066400000000000000000000007651257456735300174270ustar00rootroot00000000000000--TEST-- Test frozen services --SKIPIF-- --FILE-- --EXPECTF-- Pimple-3.0.2/ext/pimple/tests/009.phpt000066400000000000000000000005211257456735300174160ustar00rootroot00000000000000--TEST-- Test service is called as callback, and only once --SKIPIF-- --FILE-- --EXPECTF-- bool(true)Pimple-3.0.2/ext/pimple/tests/010.phpt000066400000000000000000000012051257456735300174060ustar00rootroot00000000000000--TEST-- Test service is called as callback for every callback type --SKIPIF-- --FILE-- --EXPECTF-- callme called Foo::bar array(2) { [0]=> string(3) "Foo" [1]=> string(3) "bar" }Pimple-3.0.2/ext/pimple/tests/011.phpt000066400000000000000000000006401257456735300174110ustar00rootroot00000000000000--TEST-- Test service callback throwing an exception --SKIPIF-- --FILE-- --EXPECTF-- all right!Pimple-3.0.2/ext/pimple/tests/012.phpt000066400000000000000000000007731257456735300174210ustar00rootroot00000000000000--TEST-- Test service factory --SKIPIF-- --FILE-- factory($f = function() { var_dump('called-1'); return 'ret-1';}); $p[] = $f; $p[] = function () { var_dump('called-2'); return 'ret-2'; }; var_dump($p[0]); var_dump($p[0]); var_dump($p[1]); var_dump($p[1]); ?> --EXPECTF-- string(8) "called-1" string(5) "ret-1" string(8) "called-1" string(5) "ret-1" string(8) "called-2" string(5) "ret-2" string(5) "ret-2"Pimple-3.0.2/ext/pimple/tests/013.phpt000066400000000000000000000005601257456735300174140ustar00rootroot00000000000000--TEST-- Test keys() --SKIPIF-- --FILE-- keys()); $p['foo'] = 'bar'; $p[] = 'foo'; var_dump($p->keys()); unset($p['foo']); var_dump($p->keys()); ?> --EXPECTF-- array(0) { } array(2) { [0]=> string(3) "foo" [1]=> int(0) } array(1) { [0]=> int(0) }Pimple-3.0.2/ext/pimple/tests/014.phpt000066400000000000000000000010101257456735300174040ustar00rootroot00000000000000--TEST-- Test raw() --SKIPIF-- --FILE-- raw('foo')); var_dump($p[42]); unset($p['foo']); try { $p->raw('foo'); echo "expected exception"; } catch (InvalidArgumentException $e) { } --EXPECTF-- string(8) "called-2" string(5) "ret-2" object(Closure)#%i (0) { } string(8) "called-2" string(5) "ret-2"Pimple-3.0.2/ext/pimple/tests/015.phpt000066400000000000000000000004121257456735300174120ustar00rootroot00000000000000--TEST-- Test protect() --SKIPIF-- --FILE-- protect($f); var_dump($p['foo']); --EXPECTF-- object(Closure)#%i (0) { }Pimple-3.0.2/ext/pimple/tests/016.phpt000066400000000000000000000011011257456735300174070ustar00rootroot00000000000000--TEST-- Test extend() --SKIPIF-- --FILE-- extend(12, function ($w) { var_dump($w); return 'bar'; }); /* $callable in code above */ var_dump($c('param')); --EXPECTF-- string(5) "param" string(3) "foo" string(3) "bar"Pimple-3.0.2/ext/pimple/tests/017.phpt000066400000000000000000000005771257456735300174300ustar00rootroot00000000000000--TEST-- Test extend() with exception in service extension --SKIPIF-- --FILE-- extend(12, function ($w) { throw new BadMethodCallException; }); try { $p[12]; echo "Exception expected"; } catch (BadMethodCallException $e) { } --EXPECTF-- Pimple-3.0.2/ext/pimple/tests/017_1.phpt000066400000000000000000000006011257456735300176340ustar00rootroot00000000000000--TEST-- Test extend() with exception in service factory --SKIPIF-- --FILE-- extend(12, function ($w) { return 'foobar'; }); try { $p[12]; echo "Exception expected"; } catch (BadMethodCallException $e) { } --EXPECTF-- Pimple-3.0.2/ext/pimple/tests/018.phpt000066400000000000000000000006231257456735300174210ustar00rootroot00000000000000--TEST-- Test register() --SKIPIF-- --FILE-- register(new Foo, array(42 => 'bar')); var_dump($p[42]); --EXPECTF-- object(Pimple\Container)#1 (0) { } string(3) "bar"Pimple-3.0.2/ext/pimple/tests/019.phpt000066400000000000000000000005511257456735300174220ustar00rootroot00000000000000--TEST-- Test register() returns static and is a fluent interface --SKIPIF-- --FILE-- register(new Foo)); --EXPECTF-- bool(true) Pimple-3.0.2/ext/pimple/tests/bench.phpb000066400000000000000000000013111257456735300201410ustar00rootroot00000000000000factory($factory); $p['factory'] = $factory; echo $p['factory']; echo $p['factory']; echo $p['factory']; } echo microtime(true) - $time; Pimple-3.0.2/ext/pimple/tests/bench_shared.phpb000066400000000000000000000006611257456735300214760ustar00rootroot00000000000000 Pimple-3.0.2/phpunit.xml.dist000066400000000000000000000007001257456735300161330ustar00rootroot00000000000000 ./src/Pimple/Tests Pimple-3.0.2/src/000077500000000000000000000000001257456735300135525ustar00rootroot00000000000000Pimple-3.0.2/src/Pimple/000077500000000000000000000000001257456735300150005ustar00rootroot00000000000000Pimple-3.0.2/src/Pimple/Container.php000066400000000000000000000210401257456735300174300ustar00rootroot00000000000000factories = new \SplObjectStorage(); $this->protected = new \SplObjectStorage(); foreach ($values as $key => $value) { $this->offsetSet($key, $value); } } /** * Sets a parameter or an object. * * Objects must be defined as Closures. * * Allowing any PHP callable leads to difficult to debug problems * as function names (strings) are callable (creating a function with * the same name as an existing parameter would break your container). * * @param string $id The unique identifier for the parameter or object * @param mixed $value The value of the parameter or a closure to define an object * * @throws \RuntimeException Prevent override of a frozen service */ public function offsetSet($id, $value) { if (isset($this->frozen[$id])) { throw new \RuntimeException(sprintf('Cannot override frozen service "%s".', $id)); } $this->values[$id] = $value; $this->keys[$id] = true; } /** * Gets a parameter or an object. * * @param string $id The unique identifier for the parameter or object * * @return mixed The value of the parameter or an object * * @throws \InvalidArgumentException if the identifier is not defined */ public function offsetGet($id) { if (!isset($this->keys[$id])) { throw new \InvalidArgumentException(sprintf('Identifier "%s" is not defined.', $id)); } if ( isset($this->raw[$id]) || !is_object($this->values[$id]) || isset($this->protected[$this->values[$id]]) || !method_exists($this->values[$id], '__invoke') ) { return $this->values[$id]; } if (isset($this->factories[$this->values[$id]])) { return $this->values[$id]($this); } $raw = $this->values[$id]; $val = $this->values[$id] = $raw($this); $this->raw[$id] = $raw; $this->frozen[$id] = true; return $val; } /** * Checks if a parameter or an object is set. * * @param string $id The unique identifier for the parameter or object * * @return bool */ public function offsetExists($id) { return isset($this->keys[$id]); } /** * Unsets a parameter or an object. * * @param string $id The unique identifier for the parameter or object */ public function offsetUnset($id) { if (isset($this->keys[$id])) { if (is_object($this->values[$id])) { unset($this->factories[$this->values[$id]], $this->protected[$this->values[$id]]); } unset($this->values[$id], $this->frozen[$id], $this->raw[$id], $this->keys[$id]); } } /** * Marks a callable as being a factory service. * * @param callable $callable A service definition to be used as a factory * * @return callable The passed callable * * @throws \InvalidArgumentException Service definition has to be a closure of an invokable object */ public function factory($callable) { if (!method_exists($callable, '__invoke')) { throw new \InvalidArgumentException('Service definition is not a Closure or invokable object.'); } $this->factories->attach($callable); return $callable; } /** * Protects a callable from being interpreted as a service. * * This is useful when you want to store a callable as a parameter. * * @param callable $callable A callable to protect from being evaluated * * @return callable The passed callable * * @throws \InvalidArgumentException Service definition has to be a closure of an invokable object */ public function protect($callable) { if (!method_exists($callable, '__invoke')) { throw new \InvalidArgumentException('Callable is not a Closure or invokable object.'); } $this->protected->attach($callable); return $callable; } /** * Gets a parameter or the closure defining an object. * * @param string $id The unique identifier for the parameter or object * * @return mixed The value of the parameter or the closure defining an object * * @throws \InvalidArgumentException if the identifier is not defined */ public function raw($id) { if (!isset($this->keys[$id])) { throw new \InvalidArgumentException(sprintf('Identifier "%s" is not defined.', $id)); } if (isset($this->raw[$id])) { return $this->raw[$id]; } return $this->values[$id]; } /** * Extends an object definition. * * Useful when you want to extend an existing object definition, * without necessarily loading that object. * * @param string $id The unique identifier for the object * @param callable $callable A service definition to extend the original * * @return callable The wrapped callable * * @throws \InvalidArgumentException if the identifier is not defined or not a service definition */ public function extend($id, $callable) { if (!isset($this->keys[$id])) { throw new \InvalidArgumentException(sprintf('Identifier "%s" is not defined.', $id)); } if (!is_object($this->values[$id]) || !method_exists($this->values[$id], '__invoke')) { throw new \InvalidArgumentException(sprintf('Identifier "%s" does not contain an object definition.', $id)); } if (!is_object($callable) || !method_exists($callable, '__invoke')) { throw new \InvalidArgumentException('Extension service definition is not a Closure or invokable object.'); } $factory = $this->values[$id]; $extended = function ($c) use ($callable, $factory) { return $callable($factory($c), $c); }; if (isset($this->factories[$factory])) { $this->factories->detach($factory); $this->factories->attach($extended); } return $this[$id] = $extended; } /** * Returns all defined value names. * * @return array An array of value names */ public function keys() { return array_keys($this->values); } /** * Registers a service provider. * * @param ServiceProviderInterface $provider A ServiceProviderInterface instance * @param array $values An array of values that customizes the provider * * @return static */ public function register(ServiceProviderInterface $provider, array $values = array()) { $provider->register($this); foreach ($values as $key => $value) { $this[$key] = $value; } return $this; } } Pimple-3.0.2/src/Pimple/ServiceProviderInterface.php000066400000000000000000000031231257456735300224440ustar00rootroot00000000000000value = $value; return $service; } } Pimple-3.0.2/src/Pimple/Tests/Fixtures/NonInvokable.php000066400000000000000000000023641257456735300230160ustar00rootroot00000000000000factory(function () { return new Service(); }); } } Pimple-3.0.2/src/Pimple/Tests/Fixtures/Service.php000066400000000000000000000024061257456735300220260ustar00rootroot00000000000000 */ class Service { public $value; } Pimple-3.0.2/src/Pimple/Tests/PimpleServiceProviderInterfaceTest.php000066400000000000000000000053021257456735300255560ustar00rootroot00000000000000 */ class PimpleServiceProviderInterfaceTest extends \PHPUnit_Framework_TestCase { public function testProvider() { $pimple = new Container(); $pimpleServiceProvider = new Fixtures\PimpleServiceProvider(); $pimpleServiceProvider->register($pimple); $this->assertEquals('value', $pimple['param']); $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $pimple['service']); $serviceOne = $pimple['factory']; $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $serviceOne); $serviceTwo = $pimple['factory']; $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $serviceTwo); $this->assertNotSame($serviceOne, $serviceTwo); } public function testProviderWithRegisterMethod() { $pimple = new Container(); $pimple->register(new Fixtures\PimpleServiceProvider(), array( 'anotherParameter' => 'anotherValue', )); $this->assertEquals('value', $pimple['param']); $this->assertEquals('anotherValue', $pimple['anotherParameter']); $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $pimple['service']); $serviceOne = $pimple['factory']; $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $serviceOne); $serviceTwo = $pimple['factory']; $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $serviceTwo); $this->assertNotSame($serviceOne, $serviceTwo); } } Pimple-3.0.2/src/Pimple/Tests/PimpleTest.php000066400000000000000000000320021257456735300206760ustar00rootroot00000000000000 */ class PimpleTest extends \PHPUnit_Framework_TestCase { public function testWithString() { $pimple = new Container(); $pimple['param'] = 'value'; $this->assertEquals('value', $pimple['param']); } public function testWithClosure() { $pimple = new Container(); $pimple['service'] = function () { return new Fixtures\Service(); }; $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $pimple['service']); } public function testServicesShouldBeDifferent() { $pimple = new Container(); $pimple['service'] = $pimple->factory(function () { return new Fixtures\Service(); }); $serviceOne = $pimple['service']; $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $serviceOne); $serviceTwo = $pimple['service']; $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $serviceTwo); $this->assertNotSame($serviceOne, $serviceTwo); } public function testShouldPassContainerAsParameter() { $pimple = new Container(); $pimple['service'] = function () { return new Fixtures\Service(); }; $pimple['container'] = function ($container) { return $container; }; $this->assertNotSame($pimple, $pimple['service']); $this->assertSame($pimple, $pimple['container']); } public function testIsset() { $pimple = new Container(); $pimple['param'] = 'value'; $pimple['service'] = function () { return new Fixtures\Service(); }; $pimple['null'] = null; $this->assertTrue(isset($pimple['param'])); $this->assertTrue(isset($pimple['service'])); $this->assertTrue(isset($pimple['null'])); $this->assertFalse(isset($pimple['non_existent'])); } public function testConstructorInjection() { $params = array('param' => 'value'); $pimple = new Container($params); $this->assertSame($params['param'], $pimple['param']); } /** * @expectedException \InvalidArgumentException * @expectedExceptionMessage Identifier "foo" is not defined. */ public function testOffsetGetValidatesKeyIsPresent() { $pimple = new Container(); echo $pimple['foo']; } public function testOffsetGetHonorsNullValues() { $pimple = new Container(); $pimple['foo'] = null; $this->assertNull($pimple['foo']); } public function testUnset() { $pimple = new Container(); $pimple['param'] = 'value'; $pimple['service'] = function () { return new Fixtures\Service(); }; unset($pimple['param'], $pimple['service']); $this->assertFalse(isset($pimple['param'])); $this->assertFalse(isset($pimple['service'])); } /** * @dataProvider serviceDefinitionProvider */ public function testShare($service) { $pimple = new Container(); $pimple['shared_service'] = $service; $serviceOne = $pimple['shared_service']; $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $serviceOne); $serviceTwo = $pimple['shared_service']; $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $serviceTwo); $this->assertSame($serviceOne, $serviceTwo); } /** * @dataProvider serviceDefinitionProvider */ public function testProtect($service) { $pimple = new Container(); $pimple['protected'] = $pimple->protect($service); $this->assertSame($service, $pimple['protected']); } public function testGlobalFunctionNameAsParameterValue() { $pimple = new Container(); $pimple['global_function'] = 'strlen'; $this->assertSame('strlen', $pimple['global_function']); } public function testRaw() { $pimple = new Container(); $pimple['service'] = $definition = $pimple->factory(function () { return 'foo'; }); $this->assertSame($definition, $pimple->raw('service')); } public function testRawHonorsNullValues() { $pimple = new Container(); $pimple['foo'] = null; $this->assertNull($pimple->raw('foo')); } public function testFluentRegister() { $pimple = new Container(); $this->assertSame($pimple, $pimple->register($this->getMock('Pimple\ServiceProviderInterface'))); } /** * @expectedException \InvalidArgumentException * @expectedExceptionMessage Identifier "foo" is not defined. */ public function testRawValidatesKeyIsPresent() { $pimple = new Container(); $pimple->raw('foo'); } /** * @dataProvider serviceDefinitionProvider */ public function testExtend($service) { $pimple = new Container(); $pimple['shared_service'] = function () { return new Fixtures\Service(); }; $pimple['factory_service'] = $pimple->factory(function () { return new Fixtures\Service(); }); $pimple->extend('shared_service', $service); $serviceOne = $pimple['shared_service']; $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $serviceOne); $serviceTwo = $pimple['shared_service']; $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $serviceTwo); $this->assertSame($serviceOne, $serviceTwo); $this->assertSame($serviceOne->value, $serviceTwo->value); $pimple->extend('factory_service', $service); $serviceOne = $pimple['factory_service']; $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $serviceOne); $serviceTwo = $pimple['factory_service']; $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $serviceTwo); $this->assertNotSame($serviceOne, $serviceTwo); $this->assertNotSame($serviceOne->value, $serviceTwo->value); } public function testExtendDoesNotLeakWithFactories() { if (extension_loaded('pimple')) { $this->markTestSkipped('Pimple extension does not support this test'); } $pimple = new Container(); $pimple['foo'] = $pimple->factory(function () { return; }); $pimple['foo'] = $pimple->extend('foo', function ($foo, $pimple) { return; }); unset($pimple['foo']); $p = new \ReflectionProperty($pimple, 'values'); $p->setAccessible(true); $this->assertEmpty($p->getValue($pimple)); $p = new \ReflectionProperty($pimple, 'factories'); $p->setAccessible(true); $this->assertCount(0, $p->getValue($pimple)); } /** * @expectedException \InvalidArgumentException * @expectedExceptionMessage Identifier "foo" is not defined. */ public function testExtendValidatesKeyIsPresent() { $pimple = new Container(); $pimple->extend('foo', function () {}); } public function testKeys() { $pimple = new Container(); $pimple['foo'] = 123; $pimple['bar'] = 123; $this->assertEquals(array('foo', 'bar'), $pimple->keys()); } /** @test */ public function settingAnInvokableObjectShouldTreatItAsFactory() { $pimple = new Container(); $pimple['invokable'] = new Fixtures\Invokable(); $this->assertInstanceOf('Pimple\Tests\Fixtures\Service', $pimple['invokable']); } /** @test */ public function settingNonInvokableObjectShouldTreatItAsParameter() { $pimple = new Container(); $pimple['non_invokable'] = new Fixtures\NonInvokable(); $this->assertInstanceOf('Pimple\Tests\Fixtures\NonInvokable', $pimple['non_invokable']); } /** * @dataProvider badServiceDefinitionProvider * @expectedException \InvalidArgumentException * @expectedExceptionMessage Service definition is not a Closure or invokable object. */ public function testFactoryFailsForInvalidServiceDefinitions($service) { $pimple = new Container(); $pimple->factory($service); } /** * @dataProvider badServiceDefinitionProvider * @expectedException \InvalidArgumentException * @expectedExceptionMessage Callable is not a Closure or invokable object. */ public function testProtectFailsForInvalidServiceDefinitions($service) { $pimple = new Container(); $pimple->protect($service); } /** * @dataProvider badServiceDefinitionProvider * @expectedException \InvalidArgumentException * @expectedExceptionMessage Identifier "foo" does not contain an object definition. */ public function testExtendFailsForKeysNotContainingServiceDefinitions($service) { $pimple = new Container(); $pimple['foo'] = $service; $pimple->extend('foo', function () {}); } /** * @dataProvider badServiceDefinitionProvider * @expectedException \InvalidArgumentException * @expectedExceptionMessage Extension service definition is not a Closure or invokable object. */ public function testExtendFailsForInvalidServiceDefinitions($service) { $pimple = new Container(); $pimple['foo'] = function () {}; $pimple->extend('foo', $service); } /** * Provider for invalid service definitions. */ public function badServiceDefinitionProvider() { return array( array(123), array(new Fixtures\NonInvokable()), ); } /** * Provider for service definitions. */ public function serviceDefinitionProvider() { return array( array(function ($value) { $service = new Fixtures\Service(); $service->value = $value; return $service; }), array(new Fixtures\Invokable()), ); } public function testDefiningNewServiceAfterFreeze() { $pimple = new Container(); $pimple['foo'] = function () { return 'foo'; }; $foo = $pimple['foo']; $pimple['bar'] = function () { return 'bar'; }; $this->assertSame('bar', $pimple['bar']); } /** * @expectedException \RuntimeException * @expectedExceptionMessage Cannot override frozen service "foo". */ public function testOverridingServiceAfterFreeze() { $pimple = new Container(); $pimple['foo'] = function () { return 'foo'; }; $foo = $pimple['foo']; $pimple['foo'] = function () { return 'bar'; }; } public function testRemovingServiceAfterFreeze() { $pimple = new Container(); $pimple['foo'] = function () { return 'foo'; }; $foo = $pimple['foo']; unset($pimple['foo']); $pimple['foo'] = function () { return 'bar'; }; $this->assertSame('bar', $pimple['foo']); } public function testExtendingService() { $pimple = new Container(); $pimple['foo'] = function () { return 'foo'; }; $pimple['foo'] = $pimple->extend('foo', function ($foo, $app) { return "$foo.bar"; }); $pimple['foo'] = $pimple->extend('foo', function ($foo, $app) { return "$foo.baz"; }); $this->assertSame('foo.bar.baz', $pimple['foo']); } public function testExtendingServiceAfterOtherServiceFreeze() { $pimple = new Container(); $pimple['foo'] = function () { return 'foo'; }; $pimple['bar'] = function () { return 'bar'; }; $foo = $pimple['foo']; $pimple['bar'] = $pimple->extend('bar', function ($bar, $app) { return "$bar.baz"; }); $this->assertSame('bar.baz', $pimple['bar']); } }