Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Faster version of Phalcon\DI using object handlers #1473

Merged
merged 6 commits into from Oct 30, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
746 changes: 494 additions & 252 deletions ext/di.c

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions ext/di.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ extern zend_class_entry *phalcon_di_ce;

PHALCON_INIT_CLASS(Phalcon_DI);

PHALCON_STATIC void phalcon_di_set_services(zval *this_ptr, zval *services TSRMLS_DC);

PHP_METHOD(Phalcon_DI, __construct);
PHP_METHOD(Phalcon_DI, set);
PHP_METHOD(Phalcon_DI, setShared);
Expand All @@ -39,6 +41,7 @@ PHP_METHOD(Phalcon_DI, __call);
PHP_METHOD(Phalcon_DI, setDefault);
PHP_METHOD(Phalcon_DI, getDefault);
PHP_METHOD(Phalcon_DI, reset);
PHP_METHOD(Phalcon_DI, __clone);

ZEND_BEGIN_ARG_INFO_EX(arginfo_phalcon_di_set, 0, 0, 2)
ZEND_ARG_INFO(0, name)
Expand Down Expand Up @@ -119,6 +122,7 @@ PHALCON_INIT_FUNCS(phalcon_di_method_entry){
PHP_ME(Phalcon_DI, setDefault, arginfo_phalcon_di_setdefault, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
PHP_ME(Phalcon_DI, getDefault, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
PHP_ME(Phalcon_DI, reset, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
PHP_ME(Phalcon_DI, __clone, NULL, ZEND_ACC_PUBLIC)
PHP_FE_END
};

2 changes: 1 addition & 1 deletion ext/di/factorydefault.c
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ PHP_METHOD(Phalcon_DI_FactoryDefault, __construct){
/**
* Update the internal services properties
*/
phalcon_update_property_this(this_ptr, SL("_services"), services TSRMLS_CC);
phalcon_di_set_services(this_ptr, services TSRMLS_CC);

PHALCON_MM_RESTORE();
}
Expand Down
3 changes: 2 additions & 1 deletion ext/di/factorydefault/cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,9 @@ PHP_METHOD(Phalcon_DI_FactoryDefault_CLI, __construct){
phalcon_array_update_string(&services, SL("security"), &security, PH_COPY);
phalcon_array_update_string(&services, SL("eventsManager"), &events_manager, PH_COPY);
phalcon_array_update_string(&services, SL("transactionManager"), &transaction_manager, PH_COPY);
phalcon_update_property_this(this_ptr, SL("_services"), services TSRMLS_CC);

phalcon_di_set_services(this_ptr, services TSRMLS_CC);

PHALCON_MM_RESTORE();
}

113 changes: 64 additions & 49 deletions ext/kernel/object.c
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,26 @@ int phalcon_class_exists(const zval *class_name, int autoload TSRMLS_DC) {
return 0;
}

int phalcon_class_exists_ex(zend_class_entry **zce, const zval *class_name, int autoload TSRMLS_DC) {

zend_class_entry **ce;

if (Z_TYPE_P(class_name) == IS_STRING) {
if (zend_lookup_class(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), &ce TSRMLS_CC) == SUCCESS) {
*zce = *ce;
#if PHP_VERSION_ID < 50400
return (((*ce)->ce_flags & ZEND_ACC_INTERFACE) == 0);
#else
return ((*ce)->ce_flags & (ZEND_ACC_INTERFACE | (ZEND_ACC_TRAIT - ZEND_ACC_EXPLICIT_ABSTRACT_CLASS))) == 0;
#endif
}
return 0;
}

php_error_docref(NULL TSRMLS_CC, E_WARNING, "class name must be a string");
return 0;
}

/**
* Clones an object from obj to destination
*/
Expand Down Expand Up @@ -1277,59 +1297,14 @@ int phalcon_read_class_property(zval **result, int type, char *property, int len
return FAILURE;
}

/**
* Creates a new instance dynamically. Call constructor without parameters
*/
int phalcon_create_instance(zval *return_value, const zval *class_name TSRMLS_DC){

zend_class_entry *ce;

if (Z_TYPE_P(class_name) != IS_STRING) {
phalcon_throw_exception_string(phalcon_exception_ce, "Invalid class name" TSRMLS_CC);
return FAILURE;
}

ce = zend_fetch_class(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC);
if (!ce) {
return FAILURE;
}
int phalcon_create_instance_params_ce(zval *return_value, zend_class_entry *ce, zval *params TSRMLS_DC)
{
int outcome = SUCCESS;

object_init_ex(return_value, ce);
if (phalcon_has_constructor_ce(ce)) {
return phalcon_call_method_params(NULL, NULL, return_value, SL("__construct"), zend_inline_hash_func(SS("__construct")) TSRMLS_CC, 0);
}

return SUCCESS;
}

/**
* Creates a new instance dynamically calling constructor with parameters
*/
int phalcon_create_instance_params(zval *return_value, const zval *class_name, zval *params TSRMLS_DC){

int outcome;
zend_class_entry *ce;

if (Z_TYPE_P(class_name) != IS_STRING) {
phalcon_throw_exception_string(phalcon_exception_ce, "Invalid class name" TSRMLS_CC);
return FAILURE;
}

if (Z_TYPE_P(params) != IS_ARRAY) {
phalcon_throw_exception_string(phalcon_exception_ce, "Instantiation parameters must be an array" TSRMLS_CC);
return FAILURE;
}

ce = zend_fetch_class(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC);
if (!ce) {
return FAILURE;
}

object_init_ex(return_value, ce);
outcome = SUCCESS;

if (phalcon_has_constructor_ce(ce)) {
int param_count = zend_hash_num_elements(Z_ARRVAL_P(params));
int param_count = (Z_TYPE_P(params) == IS_ARRAY) ? zend_hash_num_elements(Z_ARRVAL_P(params)) : 0;
zval *static_params[10];
zval **params_ptr, **params_arr = NULL;

Expand Down Expand Up @@ -1368,6 +1343,46 @@ int phalcon_create_instance_params(zval *return_value, const zval *class_name, z
return outcome;
}

/**
* Creates a new instance dynamically. Call constructor without parameters
*/
int phalcon_create_instance(zval *return_value, const zval *class_name TSRMLS_DC){

zend_class_entry *ce;

if (unlikely(Z_TYPE_P(class_name) != IS_STRING)) {
phalcon_throw_exception_string(phalcon_exception_ce, "Invalid class name" TSRMLS_CC);
return FAILURE;
}

ce = zend_fetch_class(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC);
if (!ce) {
return FAILURE;
}

return phalcon_create_instance_params_ce(return_value, ce, PHALCON_GLOBAL(z_null) TSRMLS_CC);
}

/**
* Creates a new instance dynamically calling constructor with parameters
*/
int phalcon_create_instance_params(zval *return_value, const zval *class_name, zval *params TSRMLS_DC){

zend_class_entry *ce;

if (unlikely(Z_TYPE_P(class_name) != IS_STRING)) {
phalcon_throw_exception_string(phalcon_exception_ce, "Invalid class name" TSRMLS_CC);
return FAILURE;
}

ce = zend_fetch_class(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC);
if (!ce) {
return FAILURE;
}

return phalcon_create_instance_params_ce(return_value, ce, params TSRMLS_CC);
}

/**
* Increments an object property
*/
Expand Down
66 changes: 34 additions & 32 deletions ext/kernel/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@
*/

/** Class Retrieving/Checking */
extern int phalcon_class_exists(const zval *class_name, int autoload TSRMLS_DC);
extern void phalcon_get_class(zval *result, zval *object, int lower TSRMLS_DC);
extern void phalcon_get_class_ns(zval *result, zval *object, int lower TSRMLS_DC);
extern void phalcon_get_ns_class(zval *result, zval *object, int lower TSRMLS_DC);
extern void phalcon_get_called_class(zval *return_value TSRMLS_DC);
extern zend_class_entry *phalcon_fetch_class(const zval *class_name TSRMLS_DC);
int phalcon_class_exists(const zval *class_name, int autoload TSRMLS_DC);
int phalcon_class_exists_ex(zend_class_entry **zce, const zval *class_name, int autoload TSRMLS_DC);
void phalcon_get_class(zval *result, zval *object, int lower TSRMLS_DC);
void phalcon_get_class_ns(zval *result, zval *object, int lower TSRMLS_DC);
void phalcon_get_ns_class(zval *result, zval *object, int lower TSRMLS_DC);
void phalcon_get_called_class(zval *return_value TSRMLS_DC);
zend_class_entry *phalcon_fetch_class(const zval *class_name TSRMLS_DC);
zend_class_entry* phalcon_fetch_self_class(TSRMLS_D);
zend_class_entry* phalcon_fetch_parent_class(TSRMLS_D);
zend_class_entry* phalcon_fetch_static_class(TSRMLS_D);
Expand All @@ -37,22 +38,22 @@ zend_class_entry* phalcon_fetch_static_class(TSRMLS_D);
} while (0)

/** Class constants */
extern int phalcon_get_class_constant(zval *return_value, zend_class_entry *ce, char *constant_name, unsigned int constant_length TSRMLS_DC);
int phalcon_get_class_constant(zval *return_value, zend_class_entry *ce, char *constant_name, unsigned int constant_length TSRMLS_DC);

/** Cloning/Instance of*/
extern int phalcon_clone(zval *destiny, zval *obj TSRMLS_DC);
extern int phalcon_instance_of(zval *result, const zval *object, const zend_class_entry *ce TSRMLS_DC);
extern int phalcon_is_instance_of(zval *object, const char *class_name, unsigned int class_length TSRMLS_DC);
int phalcon_clone(zval *destiny, zval *obj TSRMLS_DC);
int phalcon_instance_of(zval *result, const zval *object, const zend_class_entry *ce TSRMLS_DC);
int phalcon_is_instance_of(zval *object, const char *class_name, unsigned int class_length TSRMLS_DC);

/** Method exists */
extern int phalcon_method_exists(const zval *object, const zval *method_name TSRMLS_DC);
extern int phalcon_method_exists_ex(const zval *object, const char *method_name, unsigned int method_len TSRMLS_DC);
extern int phalcon_method_quick_exists_ex(const zval *object, const char *method_name, unsigned int method_len, unsigned long hash TSRMLS_DC);
int phalcon_method_exists(const zval *object, const zval *method_name TSRMLS_DC);
int phalcon_method_exists_ex(const zval *object, const char *method_name, unsigned int method_len TSRMLS_DC);
int phalcon_method_quick_exists_ex(const zval *object, const char *method_name, unsigned int method_len, unsigned long hash TSRMLS_DC);

/** Isset properties */
extern int phalcon_isset_property(zval *object, const char *property_name, unsigned int property_length TSRMLS_DC);
extern int phalcon_isset_property_quick(zval *object, const char *property_name, unsigned int property_length, unsigned long hash TSRMLS_DC);
extern int phalcon_isset_property_zval(zval *object, const zval *property TSRMLS_DC);
int phalcon_isset_property(zval *object, const char *property_name, unsigned int property_length TSRMLS_DC);
int phalcon_isset_property_quick(zval *object, const char *property_name, unsigned int property_length, unsigned long hash TSRMLS_DC);
int phalcon_isset_property_zval(zval *object, const zval *property TSRMLS_DC);

/** Reading properties */
int phalcon_read_property_this(zval **result, zval *object, char *property_name, unsigned int property_length, int silent TSRMLS_DC);
Expand All @@ -67,26 +68,26 @@ int phalcon_return_property(zval *return_value, zval **return_value_ptr, zval *o
int phalcon_return_property_quick(zval *return_value, zval **return_value_ptr, zval *object, char *property_name, unsigned int property_length, unsigned long key TSRMLS_DC);

/** Updating properties */
extern int phalcon_update_property_this(zval *object, char *property_name, unsigned int property_length, zval *value TSRMLS_DC);
extern int phalcon_update_property_long(zval *obj, char *property_name, unsigned int property_length, long value TSRMLS_DC);
extern int phalcon_update_property_string(zval *object, char *property_name, unsigned int property_length, char *str, unsigned int str_length TSRMLS_DC);
extern int phalcon_update_property_bool(zval *obj, char *property_name, unsigned int property_length, int value TSRMLS_DC);
extern int phalcon_update_property_null(zval *obj, char *property_name, unsigned int property_length TSRMLS_DC);
extern int phalcon_update_property_zval(zval *obj, char *property_name, unsigned int property_length, zval *value TSRMLS_DC);
extern int phalcon_update_property_zval_zval(zval *obj, zval *property, zval *value TSRMLS_DC);
extern int phalcon_update_property_empty_array(zend_class_entry *ce, zval *object, char *property, unsigned int property_length TSRMLS_DC);
int phalcon_update_property_this(zval *object, char *property_name, unsigned int property_length, zval *value TSRMLS_DC);
int phalcon_update_property_long(zval *obj, char *property_name, unsigned int property_length, long value TSRMLS_DC);
int phalcon_update_property_string(zval *object, char *property_name, unsigned int property_length, char *str, unsigned int str_length TSRMLS_DC);
int phalcon_update_property_bool(zval *obj, char *property_name, unsigned int property_length, int value TSRMLS_DC);
int phalcon_update_property_null(zval *obj, char *property_name, unsigned int property_length TSRMLS_DC);
int phalcon_update_property_zval(zval *obj, char *property_name, unsigned int property_length, zval *value TSRMLS_DC);
int phalcon_update_property_zval_zval(zval *obj, zval *property, zval *value TSRMLS_DC);
int phalcon_update_property_empty_array(zend_class_entry *ce, zval *object, char *property, unsigned int property_length TSRMLS_DC);

/** Updating array properties */
extern int phalcon_update_property_array(zval *object, char *property, unsigned int property_length, zval *index, zval *value TSRMLS_DC);
extern int phalcon_update_property_array_string(zval *object, char *property, unsigned int property_length, char *index, unsigned int index_length, zval *value TSRMLS_DC);
extern int phalcon_update_property_array_append(zval *object, char *property, unsigned int property_length, zval *value TSRMLS_DC);
int phalcon_update_property_array(zval *object, char *property, unsigned int property_length, zval *index, zval *value TSRMLS_DC);
int phalcon_update_property_array_string(zval *object, char *property, unsigned int property_length, char *index, unsigned int index_length, zval *value TSRMLS_DC);
int phalcon_update_property_array_append(zval *object, char *property, unsigned int property_length, zval *value TSRMLS_DC);

/** Increment/Decrement properties */
extern int phalcon_property_incr(zval *object, char *property_name, unsigned int property_length TSRMLS_DC);
extern int phalcon_property_decr(zval *object, char *property_name, unsigned int property_length TSRMLS_DC);
int phalcon_property_incr(zval *object, char *property_name, unsigned int property_length TSRMLS_DC);
int phalcon_property_decr(zval *object, char *property_name, unsigned int property_length TSRMLS_DC);

/** Unset Array properties */
extern int phalcon_unset_property_array(zval *object, char *property, unsigned int property_length, zval *index TSRMLS_DC);
int phalcon_unset_property_array(zval *object, char *property, unsigned int property_length, zval *index TSRMLS_DC);

/** Static properties */
int phalcon_read_static_property(zval **result, const char *class_name, unsigned int class_length, char *property_name, unsigned int property_length TSRMLS_DC);
Expand All @@ -97,6 +98,7 @@ int phalcon_read_class_property(zval **result, int type, char *property, int len
zval* phalcon_fetch_static_property_ce(zend_class_entry *ce, char *property, int len TSRMLS_DC);

/** Create instances */
extern int phalcon_create_instance(zval *return_value, const zval *class_name TSRMLS_DC);
extern int phalcon_create_instance_params(zval *return_value, const zval *class_name, zval *params TSRMLS_DC);
int phalcon_create_instance_params_ce(zval *return_value, zend_class_entry *ce, zval *params TSRMLS_DC);
int phalcon_create_instance(zval *return_value, const zval *class_name TSRMLS_DC);
int phalcon_create_instance_params(zval *return_value, const zval *class_name, zval *params TSRMLS_DC);

3 changes: 3 additions & 0 deletions ext/tests/issue-1455.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ include('skipif.inc');
if (!PHP_DEBUG) {
die('skip PHP must be compiled in debug mode');
}
if (!function_exists('apc_store')) {
die('skip APC or APCu is required');
}
?>
--FILE--
<?php
Expand Down
93 changes: 93 additions & 0 deletions ext/tests/issue-1473.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
--TEST--
Faster version of Phalcon\DI using object handlers - https://github.com/phalcon/cphalcon/pull/1473
--SKIPIF--
<?php include('skipif.inc'); ?>
--FILE--
<?php

class MyDI extends \Phalcon\DI
{
public function offsetGet($offset)
{
echo __METHOD__, PHP_EOL;
return parent::offsetGet($offset);
}

public function offsetSet($offset, $value)
{
echo __METHOD__, PHP_EOL;
return parent::offsetSet($offset, $value);
}

public function offsetExists($offset)
{
echo __METHOD__, PHP_EOL;
return parent::offsetExists($offset);
}

public function __call($method, $params = null)
{
echo __METHOD__, PHP_EOL;
if ('test' == $method) {
$method = 'getTest';
}

return parent::__call($method, $params);
}

public function __clone()
{
echo __METHOD__, PHP_EOL;
return parent::__clone();
}
}

$di = new MyDI();
$di['test'] = function() { return new stdClass(); };
$di['test'];
var_dump(isset($di['test']));
var_dump(get_class($di->test()));

try {
$s = serialize($di);
}
catch (Exception $e) {
echo $e->getMessage(), PHP_EOL;
}

$s = 'C:20:"Phalcon\\DI":0:{}';
$x = unserialize($s);

$s = 'O:20:"Phalcon\\DI":0:{}';
$x = unserialize($s);

$clone = clone $di;
var_dump(isset($clone['test']));
var_dump(get_class($clone->test()));

try {
$di->somethingWeird();
}
catch (\Phalcon\DI\Exception $e) {
echo $e->getMessage(), PHP_EOL;
}
?>
--EXPECTF--
MyDI::offsetSet
MyDI::offsetGet
MyDI::offsetExists
bool(true)
MyDI::__call
string(8) "stdClass"
Serialization of 'MyDI' is not allowed

Notice: unserialize(): Error at offset %d of %d bytes in %s on line %d

Notice: unserialize(): Error at offset %d of %d bytes in %s on line %d
MyDI::__clone
MyDI::offsetExists
bool(true)
MyDI::__call
string(8) "stdClass"
MyDI::__call
Call to undefined method or service 'somethingWeird'