2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2011 Derick Rethans |
6 +----------------------------------------------------------------------+
7 | Redistribution and use in source and binary forms, with or without |
8 | modification, are permitted provided that the conditions mentioned |
9 | in the accompanying LICENSE file are met (BSD, revised). |
10 +----------------------------------------------------------------------+
11 | Author: Derick Rethans <derick@derickrethans.nl> |
12 +----------------------------------------------------------------------+
21 #include "ext/standard/php_string.h"
22 #include "ext/standard/php_smart_str.h"
24 #include "Zend/zend_object_handlers.h"
25 #include "Zend/zend_interfaces.h"
26 #include "Zend/zend_exceptions.h"
29 #define Z_ADDREF_P(pz) (pz)->refcount++
32 #define FREE_DTOR(z) \
36 #if PHP_VERSION_ID >= 50300
37 #define APPLY_TSRMLS_DC TSRMLS_DC
38 #define APPLY_TSRMLS_CC TSRMLS_CC
39 #define APPLY_TSRMLS_FETCH()
41 #define APPLY_TSRMLS_DC
42 #define APPLY_TSRMLS_CC
43 #define APPLY_TSRMLS_FETCH() TSRMLS_FETCH()
46 ZEND_BEGIN_ARG_INFO_EX(twig_template_get_attribute_args
, ZEND_SEND_BY_VAL
, ZEND_RETURN_VALUE
, 6)
47 ZEND_ARG_INFO(0, template)
48 ZEND_ARG_INFO(0, object
)
49 ZEND_ARG_INFO(0, item
)
50 ZEND_ARG_INFO(0, arguments
)
51 ZEND_ARG_INFO(0, type
)
52 ZEND_ARG_INFO(0, isDefinedTest
)
55 zend_function_entry twig_functions
[] = {
56 PHP_FE(twig_template_get_attributes
, twig_template_get_attribute_args
)
61 zend_module_entry twig_module_entry
= {
62 STANDARD_MODULE_HEADER
,
71 STANDARD_MODULE_PROPERTIES
75 #ifdef COMPILE_DL_TWIG
79 int TWIG_ARRAY_KEY_EXISTS(zval
*array
, zval
*key
)
84 if (Z_TYPE_P(array
) != IS_ARRAY
) {
88 switch (Z_TYPE_P(key
)) {
90 return zend_hash_exists(Z_ARRVAL_P(array
), "", 1);
96 return zend_hash_index_exists(Z_ARRVAL_P(array
), Z_LVAL_P(key
));
99 convert_to_string(key
);
100 return zend_symtable_exists(Z_ARRVAL_P(array
), Z_STRVAL_P(key
), Z_STRLEN_P(key
) + 1);
104 int TWIG_INSTANCE_OF(zval
*object
, zend_class_entry
*interface TSRMLS_DC
)
106 if (Z_TYPE_P(object
) != IS_OBJECT
) {
109 return instanceof_function(Z_OBJCE_P(object
), interface TSRMLS_CC
);
112 int TWIG_INSTANCE_OF_USERLAND(zval
*object
, char *interface TSRMLS_DC
)
114 zend_class_entry
**pce
;
115 if (Z_TYPE_P(object
) != IS_OBJECT
) {
118 if (zend_lookup_class(interface
, strlen(interface
), &pce TSRMLS_CC
) == FAILURE
) {
121 return instanceof_function(Z_OBJCE_P(object
), *pce TSRMLS_CC
);
124 zval
*TWIG_GET_ARRAYOBJECT_ELEMENT(zval
*object
, zval
*offset TSRMLS_DC
)
126 zend_class_entry
*ce
= Z_OBJCE_P(object
);
129 if (Z_TYPE_P(object
) == IS_OBJECT
) {
130 SEPARATE_ARG_IF_REF(offset
);
131 zend_call_method_with_1_params(&object
, ce
, NULL
, "offsetget", &retval
, offset
);
133 zval_ptr_dtor(&offset
);
136 if (!EG(exception
)) {
137 zend_error(E_ERROR
, "Undefined offset for object of type %s used as array", ce
->name
);
147 int TWIG_ISSET_ARRAYOBJECT_ELEMENT(zval
*object
, zval
*offset TSRMLS_DC
)
149 zend_class_entry
*ce
= Z_OBJCE_P(object
);
152 if (Z_TYPE_P(object
) == IS_OBJECT
) {
153 SEPARATE_ARG_IF_REF(offset
);
154 zend_call_method_with_1_params(&object
, ce
, NULL
, "offsetexists", &retval
, offset
);
156 zval_ptr_dtor(&offset
);
159 if (!EG(exception
)) {
160 zend_error(E_ERROR
, "Undefined offset for object of type %s used as array", ce
->name
);
165 return (retval
&& Z_TYPE_P(retval
) == IS_BOOL
&& Z_LVAL_P(retval
));
170 char *TWIG_STRTOLOWER(const char *str
, int str_len
)
174 item_dup
= estrndup(str
, str_len
);
175 php_strtolower(item_dup
, str_len
);
179 zval
*TWIG_CALL_USER_FUNC_ARRAY(zval
*object
, char *function
, zval
*arguments TSRMLS_DC
)
191 table
= HASH_OF(arguments
);
192 args
= safe_emalloc(sizeof(zval
**), table
->nNumOfElements
, 0);
194 zend_hash_internal_pointer_reset_ex(table
, &pos
);
196 while (zend_hash_get_current_data_ex(table
, (void **)&args
[i
], &pos
) == SUCCESS
) {
198 zend_hash_move_forward_ex(table
, &pos
);
200 arg_count
= table
->nNumOfElements
;
203 MAKE_STD_ZVAL(zfunction
);
204 ZVAL_STRING(zfunction
, function
, 1);
205 fci
.size
= sizeof(fci
);
206 fci
.function_table
= EG(function_table
);
207 fci
.function_name
= zfunction
;
208 fci
.symbol_table
= NULL
;
209 #if PHP_VERSION_ID >= 50300
210 fci
.object_ptr
= object
;
212 fci
.object_pp
= &object
;
214 fci
.retval_ptr_ptr
= &retval_ptr
;
215 fci
.param_count
= arg_count
;
217 fci
.no_separation
= 0;
219 if (zend_call_function(&fci
, NULL TSRMLS_CC
) == FAILURE
) {
220 ALLOC_INIT_ZVAL(retval_ptr
);
221 ZVAL_BOOL(retval_ptr
, 0);
227 FREE_DTOR(zfunction
);
231 int TWIG_CALL_BOOLEAN(zval
*object
, char *functionName TSRMLS_DC
)
236 ret
= TWIG_CALL_USER_FUNC_ARRAY(object
, functionName
, NULL TSRMLS_CC
);
242 zval
*TWIG_GET_STATIC_PROPERTY(zval
*class, char *prop_name TSRMLS_DC
)
245 zend_class_entry
*ce
;
247 if (class == NULL
|| Z_TYPE_P(class) != IS_OBJECT
) {
251 ce
= zend_get_class_entry(class TSRMLS_CC
);
252 #if PHP_VERSION_ID >= 50400
253 tmp_zval
= zend_std_get_static_property(ce
, prop_name
, strlen(prop_name
), 0, NULL TSRMLS_CC
);
255 tmp_zval
= zend_std_get_static_property(ce
, prop_name
, strlen(prop_name
), 0 TSRMLS_CC
);
260 zval
*TWIG_GET_ARRAY_ELEMENT_ZVAL(zval
*class, zval
*prop_name TSRMLS_DC
)
265 if (class == NULL
|| Z_TYPE_P(class) != IS_ARRAY
) {
266 if (class != NULL
&& Z_TYPE_P(class) == IS_OBJECT
&& TWIG_INSTANCE_OF(class, zend_ce_arrayaccess TSRMLS_CC
)) {
267 // array access object
268 return TWIG_GET_ARRAYOBJECT_ELEMENT(class, prop_name TSRMLS_CC
);
273 switch(Z_TYPE_P(prop_name
)) {
275 zend_hash_find(HASH_OF(class), "", 1, (void**) &tmp_zval
);
280 convert_to_long(prop_name
);
282 zend_hash_index_find(HASH_OF(class), Z_LVAL_P(prop_name
), (void **) &tmp_zval
);
286 zend_symtable_find(HASH_OF(class), Z_STRVAL_P(prop_name
), Z_STRLEN_P(prop_name
) + 1, (void**) &tmp_zval
);
293 zval
*TWIG_GET_ARRAY_ELEMENT(zval
*class, char *prop_name
, int prop_name_length TSRMLS_DC
)
297 if (class == NULL
/* || Z_TYPE_P(class) != IS_ARRAY*/) {
301 if (class != NULL
&& Z_TYPE_P(class) == IS_OBJECT
&& TWIG_INSTANCE_OF(class, zend_ce_arrayaccess TSRMLS_CC
)) {
302 // array access object
306 ALLOC_INIT_ZVAL(tmp_name_zval
);
307 ZVAL_STRING(tmp_name_zval
, prop_name
, 1);
308 tmp_ret_zval
= TWIG_GET_ARRAYOBJECT_ELEMENT(class, tmp_name_zval TSRMLS_CC
);
309 FREE_DTOR(tmp_name_zval
);
313 if (zend_symtable_find(HASH_OF(class), prop_name
, prop_name_length
+1, (void**)&tmp_zval
) == SUCCESS
) {
319 zval
*TWIG_PROPERTY(zval
*object
, zval
*propname TSRMLS_DC
)
323 if (Z_OBJ_HT_P(object
)->read_property
) {
324 #if PHP_VERSION_ID >= 50400
325 tmp
= Z_OBJ_HT_P(object
)->read_property(object
, propname
, BP_VAR_IS
, NULL TSRMLS_CC
);
327 tmp
= Z_OBJ_HT_P(object
)->read_property(object
, propname
, BP_VAR_IS TSRMLS_CC
);
329 if (tmp
!= EG(uninitialized_zval_ptr
)) {
338 int TWIG_HAS_PROPERTY(zval
*object
, zval
*propname TSRMLS_DC
)
340 if (Z_OBJ_HT_P(object
)->has_property
) {
341 #if PHP_VERSION_ID >= 50400
342 return Z_OBJ_HT_P(object
)->has_property(object
, propname
, 0, NULL TSRMLS_CC
);
344 return Z_OBJ_HT_P(object
)->has_property(object
, propname
, 0 TSRMLS_CC
);
350 int TWIG_HAS_DYNAMIC_PROPERTY(zval
*object
, char *prop
, int prop_len TSRMLS_DC
)
352 if (Z_OBJ_HT_P(object
)->get_properties
) {
353 return zend_hash_quick_exists(
354 Z_OBJ_HT_P(object
)->get_properties(object TSRMLS_CC
), // the properties hash
355 prop
, // property name
356 prop_len
+ 1, // property length
357 zend_get_hash_value(prop
, prop_len
+ 1) // hash value
363 zval
*TWIG_PROPERTY_CHAR(zval
*object
, char *propname TSRMLS_DC
)
365 zval
*tmp_name_zval
, *tmp
;
367 ALLOC_INIT_ZVAL(tmp_name_zval
);
368 ZVAL_STRING(tmp_name_zval
, propname
, 1);
369 tmp
= TWIG_PROPERTY(object
, tmp_name_zval TSRMLS_CC
);
370 FREE_DTOR(tmp_name_zval
);
374 int TWIG_CALL_B_0(zval
*object
, char *method
)
379 zval
*TWIG_CALL_S(zval
*object
, char *method
, char *arg0 TSRMLS_DC
)
387 MAKE_STD_ZVAL(argument
);
388 ZVAL_STRING(argument
, arg0
, 1);
391 MAKE_STD_ZVAL(zfunction
);
392 ZVAL_STRING(zfunction
, method
, 1);
393 fci
.size
= sizeof(fci
);
394 fci
.function_table
= EG(function_table
);
395 fci
.function_name
= zfunction
;
396 fci
.symbol_table
= NULL
;
397 #if PHP_VERSION_ID >= 50300
398 fci
.object_ptr
= object
;
400 fci
.object_pp
= &object
;
402 fci
.retval_ptr_ptr
= &retval_ptr
;
405 fci
.no_separation
= 0;
407 if (zend_call_function(&fci
, NULL TSRMLS_CC
) == FAILURE
) {
408 FREE_DTOR(zfunction
);
409 zval_ptr_dtor(&argument
);
412 FREE_DTOR(zfunction
);
413 zval_ptr_dtor(&argument
);
417 int TWIG_CALL_SB(zval
*object
, char *method
, char *arg0 TSRMLS_DC
)
422 retval_ptr
= TWIG_CALL_S(object
, method
, arg0 TSRMLS_CC
);
423 success
= (retval_ptr
&& (Z_TYPE_P(retval_ptr
) == IS_BOOL
) && Z_LVAL_P(retval_ptr
));
426 zval_ptr_dtor(&retval_ptr
);
432 int TWIG_CALL_Z(zval
*object
, char *method
, zval
*arg1 TSRMLS_DC
)
442 MAKE_STD_ZVAL(zfunction
);
443 ZVAL_STRING(zfunction
, method
, 1);
444 fci
.size
= sizeof(fci
);
445 fci
.function_table
= EG(function_table
);
446 fci
.function_name
= zfunction
;
447 fci
.symbol_table
= NULL
;
448 #if PHP_VERSION_ID >= 50300
449 fci
.object_ptr
= object
;
451 fci
.object_pp
= &object
;
453 fci
.retval_ptr_ptr
= &retval_ptr
;
456 fci
.no_separation
= 0;
458 if (zend_call_function(&fci
, NULL TSRMLS_CC
) == FAILURE
) {
459 FREE_DTOR(zfunction
);
461 zval_ptr_dtor(&retval_ptr
);
466 FREE_DTOR(zfunction
);
468 success
= (retval_ptr
&& (Z_TYPE_P(retval_ptr
) == IS_BOOL
) && Z_LVAL_P(retval_ptr
));
470 zval_ptr_dtor(&retval_ptr
);
476 int TWIG_CALL_ZZ(zval
*object
, char *method
, zval
*arg1
, zval
*arg2 TSRMLS_DC
)
487 MAKE_STD_ZVAL(zfunction
);
488 ZVAL_STRING(zfunction
, method
, 1);
489 fci
.size
= sizeof(fci
);
490 fci
.function_table
= EG(function_table
);
491 fci
.function_name
= zfunction
;
492 fci
.symbol_table
= NULL
;
493 #if PHP_VERSION_ID >= 50300
494 fci
.object_ptr
= object
;
496 fci
.object_pp
= &object
;
498 fci
.retval_ptr_ptr
= &retval_ptr
;
501 fci
.no_separation
= 0;
503 if (zend_call_function(&fci
, NULL TSRMLS_CC
) == FAILURE
) {
504 FREE_DTOR(zfunction
);
508 FREE_DTOR(zfunction
);
510 success
= (retval_ptr
&& (Z_TYPE_P(retval_ptr
) == IS_BOOL
) && Z_LVAL_P(retval_ptr
));
512 zval_ptr_dtor(&retval_ptr
);
518 #ifndef Z_SET_REFCOUNT_P
519 # define Z_SET_REFCOUNT_P(pz, rc) pz->refcount = rc
520 # define Z_UNSET_ISREF_P(pz) pz->is_ref = 0
523 void TWIG_NEW(zval
*object
, char *class, zval
*arg0
, zval
*arg1 TSRMLS_DC
)
525 zend_class_entry
**pce
;
527 if (zend_lookup_class(class, strlen(class), &pce TSRMLS_CC
) == FAILURE
) {
531 Z_TYPE_P(object
) = IS_OBJECT
;
532 object_init_ex(object
, *pce
);
533 Z_SET_REFCOUNT_P(object
, 1);
534 Z_UNSET_ISREF_P(object
);
536 TWIG_CALL_ZZ(object
, "__construct", arg0
, arg1 TSRMLS_CC
);
539 static int twig_add_array_key_to_string(void *pDest APPLY_TSRMLS_DC
, int num_args
, va_list args
, zend_hash_key
*hash_key
)
543 APPLY_TSRMLS_FETCH();
545 buf
= va_arg(args
, smart_str
*);
546 joiner
= va_arg(args
, char*);
549 smart_str_appends(buf
, joiner
);
552 if (hash_key
->nKeyLength
== 0) {
553 smart_str_append_long(buf
, (long) hash_key
->h
);
556 int key_len
, tmp_len
;
557 key
= php_addcslashes(hash_key
->arKey
, hash_key
->nKeyLength
- 1, &key_len
, 0, "'\\", 2 TSRMLS_CC
);
558 tmp_str
= php_str_to_str_ex(key
, key_len
, "\0", 1, "' . \"\\0\" . '", 12, &tmp_len
, 0, NULL
);
560 smart_str_appendl(buf
, tmp_str
, tmp_len
);
568 char *TWIG_IMPLODE_ARRAY_KEYS(char *joiner
, zval
*array TSRMLS_DC
)
570 smart_str collector
= { 0, 0, 0 };
572 smart_str_appendl(&collector
, "", 0);
573 zend_hash_apply_with_arguments(HASH_OF(array
) APPLY_TSRMLS_CC
, twig_add_array_key_to_string
, 2, &collector
, joiner
);
574 smart_str_0(&collector
);
579 static void TWIG_THROW_EXCEPTION(char *exception_name TSRMLS_DC
, char *message
, ...)
583 zend_class_entry
**pce
;
585 if (zend_lookup_class(exception_name
, strlen(exception_name
), &pce TSRMLS_CC
) == FAILURE
) {
589 va_start(args
, message
);
590 vspprintf(&buffer
, 0, message
, args
);
593 zend_throw_exception_ex(*pce
, 0 TSRMLS_CC
, buffer
);
597 static void TWIG_RUNTIME_ERROR(zval
*template TSRMLS_DC
, char *message
, ...)
601 zend_class_entry
**pce
;
608 zval
*constructor_args
[3];
609 zval
*constructor_retval
;
611 if (zend_lookup_class("Twig_Error_Runtime", strlen("Twig_Error_Runtime"), &pce TSRMLS_CC
) == FAILURE
) {
615 va_start(args
, message
);
616 vspprintf(&buffer
, 0, message
, args
);
620 object_init_ex(ex
, *pce
);
622 // Call Twig_Error constructor
623 MAKE_STD_ZVAL(constructor
);
624 MAKE_STD_ZVAL(zmessage
);
625 MAKE_STD_ZVAL(lineno
);
626 MAKE_STD_ZVAL(filename
);
627 MAKE_STD_ZVAL(filename_func
);
628 MAKE_STD_ZVAL(constructor_retval
);
630 ZVAL_STRINGL(constructor
, "__construct", sizeof("__construct")-1, 1);
631 ZVAL_STRING(zmessage
, buffer
, 1);
632 ZVAL_LONG(lineno
, -1);
634 // Get template filename
635 ZVAL_STRINGL(filename_func
, "getTemplateName", sizeof("getTemplateName")-1, 1);
636 call_user_function(EG(function_table
), &template, filename_func
, filename
, 0, 0 TSRMLS_CC
);
638 constructor_args
[0] = zmessage
;
639 constructor_args
[1] = lineno
;
640 constructor_args
[2] = filename
;
641 call_user_function(EG(function_table
), &ex
, constructor
, constructor_retval
, 3, constructor_args TSRMLS_CC
);
643 zval_ptr_dtor(&constructor_retval
);
644 zval_ptr_dtor(&zmessage
);
645 zval_ptr_dtor(&lineno
);
646 zval_ptr_dtor(&filename
);
647 FREE_DTOR(constructor
);
648 FREE_DTOR(filename_func
);
651 zend_throw_exception_object(ex TSRMLS_CC
);
654 static char *TWIG_GET_CLASS_NAME(zval
*object TSRMLS_DC
)
657 zend_uint class_name_len
;
659 if (Z_TYPE_P(object
) != IS_OBJECT
) {
662 #if PHP_API_VERSION >= 20100412
663 zend_get_object_classname(object
, (const char **) &class_name
, &class_name_len TSRMLS_CC
);
665 zend_get_object_classname(object
, &class_name
, &class_name_len TSRMLS_CC
);
670 static int twig_add_method_to_class(void *pDest APPLY_TSRMLS_DC
, int num_args
, va_list args
, zend_hash_key
*hash_key
)
675 zend_function
*mptr
= (zend_function
*) pDest
;
676 APPLY_TSRMLS_FETCH();
678 if (!(mptr
->common
.fn_flags
& ZEND_ACC_PUBLIC
)) {
682 retval
= va_arg(args
, zval
*);
684 item_len
= strlen(mptr
->common
.function_name
);
685 item
= estrndup(mptr
->common
.function_name
, item_len
);
686 php_strtolower(item
, item_len
);
688 add_assoc_stringl_ex(retval
, item
, item_len
+1, item
, item_len
, 0);
693 static int twig_add_property_to_class(void *pDest APPLY_TSRMLS_DC
, int num_args
, va_list args
, zend_hash_key
*hash_key
)
695 zend_class_entry
*ce
;
697 char *class_name
, *prop_name
;
698 zend_property_info
*pptr
= (zend_property_info
*) pDest
;
699 APPLY_TSRMLS_FETCH();
701 if (!(pptr
->flags
& ZEND_ACC_PUBLIC
)) {
705 ce
= *va_arg(args
, zend_class_entry
**);
706 retval
= va_arg(args
, zval
*);
708 #if PHP_API_VERSION >= 20100412
709 zend_unmangle_property_name(pptr
->name
, pptr
->name_length
, (const char **) &class_name
, (const char **) &prop_name
);
711 zend_unmangle_property_name(pptr
->name
, pptr
->name_length
, &class_name
, &prop_name
);
714 add_assoc_string(retval
, prop_name
, prop_name
, 1);
719 static void twig_add_class_to_cache(zval
*cache
, zval
*object
, char *class_name TSRMLS_DC
)
721 zval
*class_info
, *class_methods
, *class_properties
;
722 zend_class_entry
*class_ce
;
724 class_ce
= zend_get_class_entry(object TSRMLS_CC
);
726 ALLOC_INIT_ZVAL(class_info
);
727 ALLOC_INIT_ZVAL(class_methods
);
728 ALLOC_INIT_ZVAL(class_properties
);
729 array_init(class_info
);
730 array_init(class_methods
);
731 array_init(class_properties
);
732 // add all methods to self::cache[$class]['methods']
733 zend_hash_apply_with_arguments(&class_ce
->function_table APPLY_TSRMLS_CC
, twig_add_method_to_class
, 1, class_methods
);
734 zend_hash_apply_with_arguments(&class_ce
->properties_info APPLY_TSRMLS_CC
, twig_add_property_to_class
, 2, &class_ce
, class_properties
);
736 add_assoc_zval(class_info
, "methods", class_methods
);
737 add_assoc_zval(class_info
, "properties", class_properties
);
738 add_assoc_zval(cache
, class_name
, class_info
);
741 /* {{{ proto mixed twig_template_get_attributes(TwigTemplate template, mixed object, mixed item, array arguments, string type, boolean isDefinedTest, boolean ignoreStrictCheck)
742 A C implementation of TwigTemplate::getAttribute() */
743 PHP_FUNCTION(twig_template_get_attributes
)
749 zval
*zitem
, ztmpitem
;
750 zval
*arguments
= NULL
;
754 zend_bool isDefinedTest
= 0;
755 zend_bool ignoreStrictCheck
= 0;
757 zval
*tmp_self_cache
;
760 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "ozz|asbb", &template, &object
, &zitem
, &arguments
, &type
, &type_len
, &isDefinedTest
, &ignoreStrictCheck
) == FAILURE
) {
764 // convert the item to a string
766 zval_copy_ctor(&ztmpitem
);
767 convert_to_string(&ztmpitem
);
768 item_len
= Z_STRLEN(ztmpitem
);
769 item
= estrndup(Z_STRVAL(ztmpitem
), item_len
);
770 zval_dtor(&ztmpitem
);
778 if (Twig_TemplateInterface::METHOD_CALL !== $type) {
779 $arrayItem = is_bool($item) || is_float($item) ? (int) $item : $item;
781 if ((is_array($object) && array_key_exists($arrayItem, $object))
782 || ($object instanceof ArrayAccess && isset($object[$arrayItem]))
784 if ($isDefinedTest) {
788 return $object[$arrayItem];
793 if (strcmp("method", type
) != 0) {
794 if ((TWIG_ARRAY_KEY_EXISTS(object
, zitem
))
795 || (TWIG_INSTANCE_OF(object
, zend_ce_arrayaccess TSRMLS_CC
) && TWIG_ISSET_ARRAYOBJECT_ELEMENT(object
, zitem TSRMLS_CC
))
802 ret
= TWIG_GET_ARRAY_ELEMENT_ZVAL(object
, zitem TSRMLS_CC
);
805 ret
= &EG(uninitialized_zval
);
807 RETVAL_ZVAL(ret
, 1, 0);
814 if (Twig_TemplateInterface::ARRAY_CALL === $type) {
815 if ($isDefinedTest) {
818 if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
822 if (strcmp("array", type
) == 0 || Z_TYPE_P(object
) != IS_OBJECT
) {
826 if (ignoreStrictCheck
|| !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC
), "isStrictVariables" TSRMLS_CC
)) {
830 if (is_object($object)) {
831 throw new Twig_Error_Runtime(sprintf('Key "%s" in object (with ArrayAccess) of type "%s" does not exist', $arrayItem, get_class($object)), -1, $this->getTemplateName());
832 } elseif (is_array($object)) {
833 throw new Twig_Error_Runtime(sprintf('Key "%s" for array with keys "%s" does not exist', $arrayItem, implode(', ', array_keys($object))), -1, $this->getTemplateName());
834 } elseif (Twig_TemplateInterface::ARRAY_CALL === $type) {
835 throw new Twig_Error_Runtime(sprintf('Impossible to access a key ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName());
837 throw new Twig_Error_Runtime(sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName());
842 if (Z_TYPE_P(object
) == IS_OBJECT
) {
843 TWIG_RUNTIME_ERROR(template TSRMLS_CC
, "Key \"%s\" in object (with ArrayAccess) of type \"%s\" does not exist", item
, TWIG_GET_CLASS_NAME(object TSRMLS_CC
));
844 } else if (Z_TYPE_P(object
) == IS_ARRAY
) {
845 TWIG_RUNTIME_ERROR(template TSRMLS_CC
, "Key \"%s\" for array with keys \"%s\" does not exist", item
, TWIG_IMPLODE_ARRAY_KEYS(", ", object TSRMLS_CC
));
847 char *type_name
= zend_zval_type_name(object
);
849 convert_to_string(object
);
850 TWIG_RUNTIME_ERROR(template TSRMLS_CC
,
851 (strcmp("array", type
) == 0)
852 ? "Impossible to access a key (\"%s\") on a %s variable (\"%s\")"
853 : "Impossible to access an attribute (\"%s\") on a %s variable (\"%s\")",
854 item
, type_name
, Z_STRVAL_P(object
));
855 zval_ptr_dtor(&object
);
862 if (!is_object($object)) {
863 if ($isDefinedTest) {
868 if (Z_TYPE_P(object
) != IS_OBJECT
) {
873 if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
876 throw new Twig_Error_Runtime(sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName());
879 if (ignoreStrictCheck
|| !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC
), "isStrictVariables" TSRMLS_CC
)) {
883 char *type_name
= zend_zval_type_name(object
);
885 convert_to_string_ex(&object
);
887 TWIG_RUNTIME_ERROR(template TSRMLS_CC
, "Impossible to invoke a method (\"%s\") on a %s variable (\"%s\")", item
, type_name
, Z_STRVAL_P(object
));
889 zval_ptr_dtor(&object
);
894 $class = get_class($object);
896 char *class_name
= NULL
;
899 class_name
= TWIG_GET_CLASS_NAME(object TSRMLS_CC
);
900 tmp_self_cache
= TWIG_GET_STATIC_PROPERTY(template, "cache" TSRMLS_CC
);
901 tmp_class
= TWIG_GET_ARRAY_ELEMENT(tmp_self_cache
, class_name
, strlen(class_name
) TSRMLS_CC
);
904 twig_add_class_to_cache(tmp_self_cache
, object
, class_name TSRMLS_CC
);
905 tmp_class
= TWIG_GET_ARRAY_ELEMENT(tmp_self_cache
, class_name
, strlen(class_name
) TSRMLS_CC
);
911 if (Twig_TemplateInterface::METHOD_CALL !== $type) {
912 if (isset($object->$item) || array_key_exists((string) $item, $object)) {
913 if ($isDefinedTest) {
917 if ($this->env->hasExtension('sandbox')) {
918 $this->env->getExtension('sandbox')->checkPropertyAllowed($object, $item);
921 return $object->$item;
925 if (strcmp("method", type
) != 0) {
926 zval
*tmp_properties
, *tmp_item
;
928 tmp_properties
= TWIG_GET_ARRAY_ELEMENT(tmp_class
, "properties", strlen("properties") TSRMLS_CC
);
929 tmp_item
= TWIG_GET_ARRAY_ELEMENT(tmp_properties
, item
, item_len TSRMLS_CC
);
931 if (tmp_item
|| TWIG_HAS_PROPERTY(object
, zitem TSRMLS_CC
) || TWIG_HAS_DYNAMIC_PROPERTY(object
, item
, item_len TSRMLS_CC
)) {
935 if (TWIG_CALL_SB(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC
), "hasExtension", "sandbox" TSRMLS_CC
)) {
936 TWIG_CALL_ZZ(TWIG_CALL_S(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC
), "getExtension", "sandbox" TSRMLS_CC
), "checkPropertyAllowed", object
, zitem TSRMLS_CC
);
942 ret
= TWIG_PROPERTY(object
, zitem TSRMLS_CC
);
943 RETURN_ZVAL(ret
, 1, 0);
948 if (!isset(self::$cache[$class]['methods'])) {
949 self::$cache[$class]['methods'] = array_change_key_case(array_flip(get_class_methods($object)));
952 $lcItem = strtolower($item);
953 if (isset(self::$cache[$class]['methods'][$lcItem])) {
954 $method = (string) $item;
955 } elseif (isset(self::$cache[$class]['methods']['get'.$lcItem])) {
956 $method = 'get'.$item;
957 } elseif (isset(self::$cache[$class]['methods']['is'.$lcItem])) {
958 $method = 'is'.$item;
959 } elseif (isset(self::$cache[$class]['methods']['__call'])) {
960 $method = (string) $item;
963 char *lcItem
= TWIG_STRTOLOWER(item
, item_len
);
966 char *tmp_method_name_get
;
967 char *tmp_method_name_is
;
970 lcItem_length
= strlen(lcItem
);
971 tmp_method_name_get
= emalloc(4 + lcItem_length
);
972 tmp_method_name_is
= emalloc(3 + lcItem_length
);
974 sprintf(tmp_method_name_get
, "get%s", lcItem
);
975 sprintf(tmp_method_name_is
, "is%s", lcItem
);
977 tmp_methods
= TWIG_GET_ARRAY_ELEMENT(tmp_class
, "methods", strlen("methods") TSRMLS_CC
);
979 if (TWIG_GET_ARRAY_ELEMENT(tmp_methods
, lcItem
, lcItem_length TSRMLS_CC
)) {
981 } else if (TWIG_GET_ARRAY_ELEMENT(tmp_methods
, tmp_method_name_get
, lcItem_length
+ 3 TSRMLS_CC
)) {
982 method
= tmp_method_name_get
;
983 } else if (TWIG_GET_ARRAY_ELEMENT(tmp_methods
, tmp_method_name_is
, lcItem_length
+ 2 TSRMLS_CC
)) {
984 method
= tmp_method_name_is
;
985 } else if (TWIG_GET_ARRAY_ELEMENT(tmp_methods
, "__call", 6 TSRMLS_CC
)) {
989 if ($isDefinedTest) {
993 if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
997 throw new Twig_Error_Runtime(sprintf('Method "%s" for object "%s" does not exist', $item, get_class($object)), -1, $this->getTemplateName());
1000 if ($isDefinedTest) {
1005 efree(tmp_method_name_get
);
1006 efree(tmp_method_name_is
);
1009 if (isDefinedTest
) {
1012 if (ignoreStrictCheck
|| !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC
), "isStrictVariables" TSRMLS_CC
)) {
1015 TWIG_RUNTIME_ERROR(template TSRMLS_CC
, "Method \"%s\" for object \"%s\" does not exist", item
, TWIG_GET_CLASS_NAME(object TSRMLS_CC
));
1019 if (isDefinedTest
) {
1020 efree(tmp_method_name_get
);
1021 efree(tmp_method_name_is
);
1026 if ($this->env->hasExtension('sandbox')) {
1027 $this->env->getExtension('sandbox')->checkMethodAllowed($object, $method);
1030 if (TWIG_CALL_SB(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC
), "hasExtension", "sandbox" TSRMLS_CC
)) {
1031 TWIG_CALL_ZZ(TWIG_CALL_S(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC
), "getExtension", "sandbox" TSRMLS_CC
), "checkMethodAllowed", object
, zitem TSRMLS_CC
);
1033 if (EG(exception
)) {
1034 efree(tmp_method_name_get
);
1035 efree(tmp_method_name_is
);
1040 $ret = call_user_func_array(array($object, $method), $arguments);
1042 ret
= TWIG_CALL_USER_FUNC_ARRAY(object
, method
, arguments TSRMLS_CC
);
1044 efree(tmp_method_name_get
);
1045 efree(tmp_method_name_is
);
1049 // useful when calling a template method from a template
1050 // this is not supported but unfortunately heavily used in the Symfony profiler
1051 if ($object instanceof Twig_TemplateInterface) {
1052 return $ret === '' ? '' : new Twig_Markup($ret, $this->env->getCharset());
1057 // ret can be null, if e.g. the called method throws an exception
1059 if (TWIG_INSTANCE_OF_USERLAND(object
, "Twig_TemplateInterface" TSRMLS_CC
)) {
1060 if (Z_STRLEN_P(ret
) != 0) {
1061 zval
*charset
= TWIG_CALL_USER_FUNC_ARRAY(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC
), "getCharset", NULL TSRMLS_CC
);
1062 TWIG_NEW(return_value
, "Twig_Markup", ret
, charset TSRMLS_CC
);
1063 zval_ptr_dtor(&charset
);
1065 zval_ptr_dtor(&ret
);
1071 RETVAL_ZVAL(ret
, 1, 0);
1073 zval_ptr_dtor(&ret
);