Singleton.c

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (C) 2006-2007 by Konstantin V. Arkhipov                     *
00003  *                                                                         *
00004  *   This program is free software; you can redistribute it and/or modify  *
00005  *   it under the terms of the GNU Lesser General Public License as        *
00006  *   published by the Free Software Foundation; either version 3 of the    *
00007  *   License, or (at your option) any later version.                       *
00008  *                                                                         *
00009  ***************************************************************************/
00010 /* $Id: Singleton.c 4687 2007-12-09 18:57:18Z voxus $ */
00011 
00012 #include "onphp.h"
00013 #include "onphp_core.h"
00014 
00015 #include "zend_globals.h"
00016 #include "zend_exceptions.h"
00017 
00018 #include "core/Base/Singleton.h"
00019 #include "core/Exceptions.h"
00020 
00021 // request's scope
00022 static zval *instances = NULL;
00023 
00024 /* protected */     ONPHP_METHOD(Singleton, __construct)    {/*_*/}
00025 /* final private */ ONPHP_METHOD(Singleton, __clone)        {/*_*/}
00026 /* final private */ ONPHP_METHOD(Singleton, __sleep)        {/*_*/}
00027 
00028 ONPHP_METHOD(Singleton, getInstance)
00029 {
00030     char *name;
00031     int length, argc = ZEND_NUM_ARGS();
00032     zend_class_entry **cep;
00033     zval *object, *args;
00034     zval **stored;
00035     zval ***params = NULL;
00036     
00037     if (argc < 1) {
00038         WRONG_PARAM_COUNT;
00039     }
00040 
00041     params = safe_emalloc(sizeof(zval **), argc, 0);
00042     
00043     if (zend_get_parameters_array_ex(argc, params) == FAILURE) {
00044         zend_throw_exception_ex(
00045             onphp_ce_BaseException,
00046             0 TSRMLS_CC,
00047             "Failed to get calling arguments for object creation"
00048         );
00049         efree(params);
00050         RETURN_NULL();
00051     }
00052     
00053     // replica of historical Singleton's behaviour
00054     if (argc > 2) {
00055         int i;
00056         ALLOC_INIT_ZVAL(args);
00057         array_init(args);
00058         
00059         for (i = 1; i < argc; i++) {
00060             add_next_index_zval(args, *params[i]);
00061         }
00062         
00063         params[1] = &args;
00064         argc = 2;
00065     }
00066     
00067     name = estrdup(Z_STRVAL_PP(params[0]));
00068     
00069     length = strlen(name);
00070     
00071     if (
00072         zend_hash_find(
00073             Z_ARRVAL_P(instances),
00074             name,
00075             length + 1,
00076             (void **) &stored
00077         )
00078         == SUCCESS
00079     ) {
00080         efree(params);
00081         efree(name);
00082         
00083         object = *stored;
00084         
00085         zval_copy_ctor(object);
00086     } else {
00087         // stolen from Reflection's newInstance()
00088         if (zend_lookup_class(name, length, &cep TSRMLS_CC) == SUCCESS) {
00089             zval *retval_ptr;
00090             zend_fcall_info fci;
00091             zend_fcall_info_cache fcc;
00092             zend_class_entry *ce = *cep;
00093             
00094             // can use ce->name instead now
00095             efree(name);
00096             
00097             if (!instanceof_function(ce, onphp_ce_Singleton TSRMLS_CC)) {
00098                 zend_throw_exception_ex(
00099                     onphp_ce_WrongArgumentException,
00100                     0 TSRMLS_CC,
00101                     "Class '%s' is something not a Singleton's child",
00102                     ce->name
00103                 );
00104                 efree(params);
00105                 return;
00106             }
00107             
00108             // we can call protected consturctors,
00109             // since all classes are childs of Singleton
00110             if (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE) {
00111                 zend_throw_exception_ex(
00112                     onphp_ce_BaseException,
00113                     0 TSRMLS_CC,
00114                     "Can not call private constructor for '%s' creation",
00115                     ce->name
00116                 );
00117                 efree(params);
00118                 return;
00119             } else if (ce->constructor->common.fn_flags & ZEND_ACC_PUBLIC) {
00120                 zend_throw_exception_ex(
00121                     onphp_ce_BaseException,
00122                     0 TSRMLS_CC,
00123                     "Don't want to deal with '%s' class "
00124                         "due to public constructor there",
00125                     ce->name
00126                 );
00127                 efree(params);
00128                 return;
00129             }
00130             
00131             MAKE_STD_ZVAL(object);
00132             object_init_ex(object, ce);
00133             
00134             fci.size = sizeof(fci);
00135             fci.function_table = EG(function_table);
00136             fci.function_name = NULL;
00137             fci.symbol_table = NULL;
00138             fci.object_pp = &object;
00139             fci.retval_ptr_ptr = &retval_ptr;
00140             fci.param_count = argc - 1;
00141             fci.params = params + 1;
00142             
00143             fcc.initialized = 1;
00144             fcc.function_handler = ce->constructor;
00145             fcc.calling_scope = EG(scope);
00146             fcc.object_pp = &object;
00147             
00148             if (zend_call_function(&fci, &fcc TSRMLS_CC) == FAILURE) {
00149                 zend_throw_exception_ex(
00150                     onphp_ce_BaseException,
00151                     0 TSRMLS_CC,
00152                     "Failed to call '%s' constructor",
00153                     ce->name
00154                 );
00155             }
00156             
00157             efree(params);
00158             
00159             if (retval_ptr) {
00160                 zval_ptr_dtor(&retval_ptr);
00161             }
00162             
00163             if (EG(exception)) {
00164                 return;
00165             }
00166             
00167             add_assoc_zval_ex(instances, ce->name, length + 1, object);
00168         }
00169     }
00170     
00171     RETURN_ZVAL(object, 1, 0);
00172 }
00173 
00174 ONPHP_METHOD(Singleton, getAllInstances)
00175 {
00176     RETURN_ZVAL(instances, 1, 0);
00177 }
00178 
00179 PHP_RINIT_FUNCTION(Singleton)
00180 {
00181     ALLOC_INIT_ZVAL(instances);
00182     array_init(instances);
00183     
00184     return SUCCESS;
00185 }
00186 
00187 PHP_RSHUTDOWN_FUNCTION(Singleton)
00188 {
00189     zval_ptr_dtor(&instances);
00190 
00191     return SUCCESS;
00192 }
00193 
00194 static ONPHP_ARGINFO_ONE;
00195 
00196 zend_function_entry onphp_funcs_Singleton[] = {
00197     ONPHP_ME(Singleton, __construct,        NULL, ZEND_ACC_PROTECTED | ZEND_ACC_CTOR)
00198     ONPHP_ME(Singleton, getInstance,        arginfo_one, ZEND_ACC_FINAL | ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
00199     ONPHP_ME(Singleton, getAllInstances,    NULL, ZEND_ACC_FINAL | ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
00200     ONPHP_ME(Singleton, __clone,            NULL, ZEND_ACC_FINAL | ZEND_ACC_PRIVATE)
00201     ONPHP_ME(Singleton, __sleep,            NULL, ZEND_ACC_FINAL | ZEND_ACC_PRIVATE)
00202     {NULL, NULL, NULL}
00203 };

Generated on Sun Dec 9 21:56:23 2007 for onPHP by  doxygen 1.5.4