1 /*******************************************************************************
2 Copyright (c) 2016, Michael Wallner <mike@php.net>.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
8 * Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
18 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *******************************************************************************/
26 #include "php_psi_stdinc.h"
33 #include "Zend/zend_interfaces.h"
34 #include "ext/spl/spl_iterators.h"
36 zend_long
psi_zval_count(zval
*zvalue
)
38 /* mimic PHP count() */
42 switch (Z_TYPE_P(zvalue
)) {
50 count
= zend_array_count(Z_ARRVAL_P(zvalue
));
54 if (Z_OBJ_HT_P(zvalue
)->count_elements
) {
55 if (SUCCESS
== Z_OBJ_HT_P(zvalue
)->count_elements(zvalue
, &count
)) {
60 if (instanceof_function(Z_OBJCE_P(zvalue
), spl_ce_Countable
)) {
61 zend_call_method_with_0_params(zvalue
, NULL
, NULL
, "count", &retval
);
62 if (Z_TYPE(retval
) != IS_UNDEF
) {
63 count
= zval_get_long(&retval
);
64 zval_ptr_dtor(&retval
);
73 int psi_internal_type(struct psi_impl_type
*type
)
92 zend_internal_arg_info
*psi_internal_arginfo(struct psi_impl
*impl
)
94 size_t i
= 0, argc
= psi_plist_count(impl
->func
->args
);
95 zend_internal_arg_info
*aip
;
96 zend_internal_function_info
*fi
;
97 struct psi_impl_arg
*iarg
;
99 aip
= pecalloc(argc
+ 1 + !!impl
->func
->vararg
, sizeof(*aip
), 1);
101 fi
= (zend_internal_function_info
*) &aip
[0];
102 #ifdef ZEND_TYPE_ENCODE
103 fi
->type
= ZEND_TYPE_ENCODE(psi_internal_type(impl
->func
->return_type
), 1);
106 fi
->type_hint
= psi_internal_type(impl
->func
->return_type
);
108 fi
->required_num_args
= psi_impl_num_min_args(impl
);
109 fi
->return_reference
= impl
->func
->return_reference
;
111 if (impl
->func
->vararg
) {
112 struct psi_impl_arg
*vararg
= impl
->func
->vararg
;
113 zend_internal_arg_info
*ai
= &aip
[argc
];
115 ai
->name
= vararg
->var
->name
->val
;
116 #ifdef ZEND_TYPE_ENCODE
117 ai
->type
= ZEND_TYPE_ENCODE(psi_internal_type(vararg
->type
), 1);
120 ai
->type_hint
= psi_internal_type(vararg
->type
);
122 if (vararg
->var
->reference
) {
123 ai
->pass_by_reference
= 1;
128 while (psi_plist_get(impl
->func
->args
, i
++, &iarg
)) {
129 zend_internal_arg_info
*ai
= &aip
[i
];
131 ai
->name
= iarg
->var
->name
->val
;
132 #ifdef ZEND_TYPE_ENCODE
133 ai
->type
= ZEND_TYPE_ENCODE(psi_internal_type(iarg
->type
), 1);
136 ai
->type_hint
= psi_internal_type(iarg
->type
);
138 if (iarg
->var
->reference
) {
139 ai
->pass_by_reference
= 1;
149 void psi_set_void(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
)
157 impl_val
*psi_let_void(impl_val
*tmp
, struct psi_decl_arg
*spec
, token_t impl_type
, impl_val
*ival
, zval
*zvalue
, void **to_free
)
163 * set $ivar = zval(dvar)
165 void psi_set_zval(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
) {
166 RETVAL_ZVAL(ret_val
->ptr
, 1, 0);
170 * let dvar = zval($ivar)
172 impl_val
*psi_let_zval(impl_val
*tmp
, struct psi_decl_arg
*spec
, token_t impl_type
, impl_val
*ival
, zval
*zvalue
, void **to_free
)
174 *to_free
= tmp
->ptr
= emalloc(sizeof(zval
));
175 ZVAL_COPY_VALUE(tmp
->ptr
, zvalue
);
180 * return to_bool(dvar)
182 void psi_set_to_bool(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
)
184 psi_set_to_int(return_value
, set
, ret_val
, frame
);
185 convert_to_boolean(return_value
);
188 static inline impl_val
*psi_val_boolval(impl_val
*tmp
, token_t real_type
, zend_bool boolval
) {
190 case PSI_T_INT8
: tmp
->i8
= boolval
; break;
191 case PSI_T_UINT8
: tmp
->u8
= boolval
; break;
192 case PSI_T_INT16
: tmp
->i16
= boolval
; break;
193 case PSI_T_UINT16
: tmp
->u16
= boolval
; break;
194 case PSI_T_INT32
: tmp
->i32
= boolval
; break;
195 case PSI_T_UINT32
: tmp
->u32
= boolval
; break;
196 case PSI_T_INT64
: tmp
->i64
= boolval
; break;
197 case PSI_T_UINT64
: tmp
->u64
= boolval
; break;
199 case PSI_T_INT128
: tmp
->i128
= boolval
; break;
200 case PSI_T_UINT128
: tmp
->u128
= boolval
; break;
202 case PSI_T_FLOAT
: tmp
->fval
= boolval
; break;
203 case PSI_T_DOUBLE
: tmp
->dval
= boolval
; break;
204 #ifdef HAVE_LONG_DOUBLE
205 case PSI_T_LONG_DOUBLE
: tmp
->ldval
= boolval
; break;
207 EMPTY_SWITCH_DEFAULT_CASE();
213 * let dvar = boolval($ivar)
215 impl_val
*psi_let_boolval(impl_val
*tmp
, struct psi_decl_arg
*spec
, token_t impl_type
, impl_val
*ival
, zval
*zvalue
, void **to_free
)
218 token_t real_type
= spec
? psi_decl_type_get_real(spec
->type
)->type
: PSI_T_UINT8
;
220 if (ival
&& impl_type
== PSI_T_BOOL
) {
221 boolval
= ival
->zend
.bval
;
223 boolval
= zend_is_true(zvalue
);
226 return psi_val_boolval(tmp
, real_type
, boolval
);
230 * set $ivar = to_int(*dvar)
232 void psi_set_to_int(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
)
234 struct psi_decl_var
*var
= psi_set_exp_get_decl_var(set
);
235 token_t t
= psi_decl_type_get_real(var
->arg
->type
)->type
;
236 impl_val
*v
= deref_impl_val(ret_val
, var
);
239 case PSI_T_INT8
: RETVAL_LONG(v
->i8
); break;
240 case PSI_T_UINT8
: RETVAL_LONG(v
->u8
); break;
241 case PSI_T_INT16
: RETVAL_LONG(v
->i16
); break;
242 case PSI_T_UINT16
: RETVAL_LONG(v
->u16
); break;
244 case PSI_T_INT32
: RETVAL_LONG(v
->i32
); break;
245 case PSI_T_UINT32
: RETVAL_LONG(v
->u32
); break;
246 case PSI_T_INT64
: RETVAL_LONG(v
->i64
); break;
247 case PSI_T_UINT64
: RETVAL_LONG_DOUBLE_STR(v
->u64
,); break;
249 case PSI_T_INT128
: RETVAL_LONG_DOUBLE_STR(v
->i128
, is_signed
=true); break;
250 case PSI_T_UINT128
: RETVAL_LONG_DOUBLE_STR(v
->u128
,); break;
253 RETVAL_DOUBLE((double) v
->fval
);
254 convert_to_long(return_value
);
257 RETVAL_DOUBLE(v
->dval
);
258 convert_to_long(return_value
);
260 #ifdef HAVE_LONG_DOUBLE
261 case PSI_T_LONG_DOUBLE
:
262 RETVAL_DOUBLE((double) v
->ldval
);
263 convert_to_long(return_value
);
266 EMPTY_SWITCH_DEFAULT_CASE();
270 static inline impl_val
*psi_val_intval(impl_val
*tmp
, token_t real_type
, zend_long intval
) {
272 case PSI_T_INT8
: tmp
->i8
= intval
; break;
273 case PSI_T_UINT8
: tmp
->u8
= intval
; break;
274 case PSI_T_INT16
: tmp
->i16
= intval
; break;
275 case PSI_T_UINT16
: tmp
->u16
= intval
; break;
277 case PSI_T_INT32
: tmp
->i32
= intval
; break;
278 case PSI_T_UINT32
: tmp
->u32
= intval
; break;
279 case PSI_T_INT64
: tmp
->i64
= intval
; break;
280 case PSI_T_UINT64
: tmp
->u64
= intval
; break;
282 case PSI_T_INT128
: tmp
->i128
= intval
; break;
283 case PSI_T_UINT128
: tmp
->u128
= intval
; break;
285 case PSI_T_FLOAT
: tmp
->fval
= intval
; break;
286 case PSI_T_DOUBLE
: tmp
->dval
= intval
; break;
287 #ifdef HAVE_LONG_DOUBLE
288 case PSI_T_LONG_DOUBLE
: tmp
->ldval
= intval
; break;
290 EMPTY_SWITCH_DEFAULT_CASE();
297 void psi_strto_i128(char *ptr
, char *end
, token_t real_type
, impl_val
*val
) {
298 unsigned __int128 i
= 0;
299 bool oct
= false, hex
= false, sign
= false;
303 } else if (*ptr
== '-') {
306 } else if (*ptr
== '\\') {
312 case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':
326 case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':
336 case 'a':case 'b':case 'c':case 'd':case 'e':case 'f':
341 i
+= 10 + (*ptr
- 'a');
343 case 'A':case 'B':case 'C':case 'D':case 'E':case 'F':
348 i
+= 10 + (*ptr
- 'A');
352 zend_error(E_WARNING
, "A non well formed numeric value encountered");
359 if (real_type
== PSI_T_UINT128
) {
376 * let dvar = intval($ivar)
378 impl_val
*psi_let_intval(impl_val
*tmp
, struct psi_decl_arg
*spec
, token_t impl_type
, impl_val
*ival
, zval
*zvalue
, void **to_free
)
381 token_t real_type
= spec
? psi_decl_type_get_real(spec
->type
)->type
: PSI_T_INT64
;
384 if (ival
&& impl_type
== PSI_T_INT
) {
385 intval
= ival
->zend
.lval
;
387 } else if ((real_type
== PSI_T_UINT128
|| real_type
== PSI_T_INT128
) &&
388 !((Z_TYPE_P(zvalue
) == IS_TRUE
|| Z_TYPE_P(zvalue
) == IS_FALSE
|| Z_TYPE_P(zvalue
) == IS_LONG
|| Z_TYPE_P(zvalue
) == IS_DOUBLE
|| Z_TYPE_P(zvalue
) == IS_NULL
))) {
389 zend_string
*str
= zval_get_string(zvalue
);
390 psi_strto_i128(str
->val
, str
->val
+ str
->len
, real_type
, tmp
);
391 zend_string_release(str
);
395 intval
= zval_get_long(zvalue
);
398 return psi_val_intval(tmp
, real_type
, intval
);
402 * set $ivar = to_float(dvar)
404 void psi_set_to_float(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
)
406 struct psi_decl_var
*var
= psi_set_exp_get_decl_var(set
);
407 token_t t
= psi_decl_type_get_real(var
->arg
->type
)->type
;
408 impl_val
*v
= deref_impl_val(ret_val
, var
);
411 case PSI_T_FLOAT
: RETVAL_DOUBLE((double) v
->fval
); break;
412 case PSI_T_DOUBLE
: RETVAL_DOUBLE(v
->dval
); break;
413 #ifdef HAVE_LONG_DOUBLE
414 case PSI_T_LONG_DOUBLE
: RETVAL_DOUBLE((double) v
->ldval
); break;
416 case PSI_T_INT8
: RETVAL_DOUBLE((double) v
->i8
); break;
417 case PSI_T_UINT8
: RETVAL_DOUBLE((double) v
->u8
); break;
418 case PSI_T_INT16
: RETVAL_DOUBLE((double) v
->i16
); break;
419 case PSI_T_UINT16
: RETVAL_DOUBLE((double) v
->u16
); break;
420 case PSI_T_INT32
: RETVAL_DOUBLE((double) v
->i32
); break;
421 case PSI_T_UINT32
: RETVAL_DOUBLE((double) v
->u32
); break;
422 case PSI_T_INT64
: RETVAL_DOUBLE((double) v
->i64
); break;
423 case PSI_T_UINT64
: RETVAL_DOUBLE((double) v
->u64
); break;
425 case PSI_T_INT128
: RETVAL_DOUBLE((double) v
->i128
); break;
426 case PSI_T_UINT128
: RETVAL_DOUBLE((double) v
->u128
); break;
428 EMPTY_SWITCH_DEFAULT_CASE();
432 static inline impl_val
*psi_val_floatval(impl_val
*tmp
, token_t real_type
, double floatval
) {
434 case PSI_T_INT8
: tmp
->i8
= floatval
; break;
435 case PSI_T_UINT8
: tmp
->u8
= floatval
; break;
436 case PSI_T_INT16
: tmp
->i16
= floatval
; break;
437 case PSI_T_UINT16
: tmp
->u16
= floatval
; break;
438 case PSI_T_INT32
: tmp
->i32
= floatval
; break;
439 case PSI_T_UINT32
: tmp
->u32
= floatval
; break;
440 case PSI_T_INT64
: tmp
->i64
= floatval
; break;
441 case PSI_T_UINT64
: tmp
->u64
= floatval
; break;
443 case PSI_T_INT128
: tmp
->i128
= floatval
; break;
444 case PSI_T_UINT128
: tmp
->u128
= floatval
; break;
446 case PSI_T_FLOAT
: tmp
->fval
= floatval
; break;
447 case PSI_T_DOUBLE
: tmp
->dval
= floatval
; break;
448 #ifdef HAVE_LONG_DOUBLE
449 case PSI_T_LONG_DOUBLE
: tmp
->ldval
= floatval
; break;
451 EMPTY_SWITCH_DEFAULT_CASE();
458 * let dvar = floatval($ivar)
460 impl_val
*psi_let_floatval(impl_val
*tmp
, struct psi_decl_arg
*spec
, token_t impl_type
, impl_val
*ival
, zval
*zvalue
, void **to_free
)
463 token_t real_type
= spec
? psi_decl_type_get_real(spec
->type
)->type
: PSI_T_DOUBLE
;
465 if (ival
&& (impl_type
== PSI_T_FLOAT
|| impl_type
== PSI_T_DOUBLE
)) {
466 floatval
= ival
->dval
;
468 floatval
= zval_get_double(zvalue
);
471 return psi_val_floatval(tmp
, real_type
, floatval
);
475 * set $ivar = to_string(dvar)
477 void psi_set_to_string(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
)
479 struct psi_decl_var
*var
= psi_set_exp_get_decl_var(set
);
480 impl_val
*ptr
= deref_impl_val(ret_val
, var
);
483 if (var
->arg
->var
->array_size
&& var
->arg
->var
->pointer_level
== 1) {
492 RETVAL_EMPTY_STRING();
497 * set $ivar = to_string(dvar, num_exp)
499 void psi_set_to_stringl(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
)
501 struct psi_decl_var
*var
= psi_set_exp_get_decl_var(set
);
502 char *str
= deref_impl_val(ret_val
, var
)->ptr
;
505 struct psi_set_exp
*sub_exp
;
507 psi_plist_get(set
->inner
, 0, &sub_exp
);
508 RETVAL_STRINGL(str
, psi_num_exp_get_long(sub_exp
->data
.num
, frame
, NULL
));
510 RETVAL_EMPTY_STRING();
515 * let dvar = strval($ivar)
517 impl_val
*psi_let_strval(impl_val
*tmp
, struct psi_decl_arg
*spec
, token_t impl_type
, impl_val
*ival
, zval
*zvalue
, void **to_free
)
519 if (ival
&& impl_type
== PSI_T_STRING
) {
520 if (ival
->zend
.str
) {
521 tmp
->ptr
= ival
->zend
.str
->val
;
526 zend_string
*zs
= zval_get_string(zvalue
);
527 tmp
->ptr
= estrdup(zs
->val
);
529 zend_string_release(zs
);
536 * let dvar = pathval($ivar)
538 impl_val
*psi_let_pathval(impl_val
*tmp
, struct psi_decl_arg
*spec
, token_t impl_type
, impl_val
*ival
, zval
*zvalue
, void **to_free
)
540 tmp
= psi_let_strval(tmp
, spec
, impl_type
, ival
, zvalue
, to_free
);
541 if (SUCCESS
!= php_check_open_basedir(tmp
->ptr
)) {
544 return *to_free
= NULL
;
550 * let dvar = strlen($ivar)
552 impl_val
*psi_let_strlen(impl_val
*tmp
, struct psi_decl_arg
*spec
, token_t impl_type
, impl_val
*ival
, zval
*zvalue
, void **to_free
)
554 if (ival
&& impl_type
== PSI_T_STRING
) {
555 if (ival
->zend
.str
) {
556 tmp
->u64
= ival
->zend
.str
->len
;
561 zend_string
*zs
= zval_get_string(zvalue
);
563 zend_string_release(zs
);
567 psi_calc_cast(PSI_T_UINT64
, tmp
, psi_decl_type_get_real(spec
->type
)->type
, tmp
);
573 static impl_val
*iterate(impl_val
*val
, size_t size
, unsigned i
, impl_val
*tmp
)
575 memset(tmp
, 0, sizeof(*tmp
));
576 memcpy(tmp
, ((char *) val
) + size
* i
, size
);
582 * set $ivar = to_array(dvar,
583 * $foo = to_int(d_foo),
584 * $bar = to_string(d_bar),
585 * $baz = to_array(*d_next, ...)
587 void psi_set_to_recursive(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*r_val
, struct psi_call_frame
*frame
) {
588 set
->outer
->data
.func
->handler(return_value
, set
, r_val
, frame
);
592 * set $ivar = to_array(dvar, to_string(*dvar));
594 void psi_set_to_array_simple(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*r_val
, struct psi_call_frame
*frame
)
596 struct psi_set_exp
*sub_exp
;
597 struct psi_decl_var
*var
;
602 array_init(return_value
);
604 var
= psi_set_exp_get_decl_var(set
);
605 ret_val
= deref_impl_val(r_val
, var
);
606 if ((intptr_t) ret_val
<= (intptr_t) 0) {
610 psi_plist_get(set
->inner
, 0, &sub_exp
);
612 size
= psi_decl_arg_get_size(var
->arg
);
613 for (ptr
= ret_val
->ptr
; *(void **) ptr
; ptr
+= size
) {
617 sub_exp
->data
.func
->handler(&ele
, sub_exp
, (void *) ptr
, frame
);
618 add_next_index_zval(return_value
, &ele
);
623 * set $ivar = to_array(dvar, num_exp, to_string(*dvar));
625 void psi_set_to_array_counted(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*r_val
, struct psi_call_frame
*frame
)
627 struct psi_set_exp
*sub_exp
;
628 struct psi_decl_var
*var
;
634 array_init(return_value
);
636 var
= psi_set_exp_get_decl_var(set
);
637 ret_val
= deref_impl_val(r_val
, var
);
638 if ((intptr_t) ret_val
<= (intptr_t) 0) {
642 psi_plist_get(set
->inner
, 0, &sub_exp
);
643 count
= psi_num_exp_get_long(sub_exp
->data
.num
, frame
, NULL
);
644 psi_plist_get(set
->inner
, 1, &sub_exp
);
646 size
= psi_decl_var_get_size(psi_set_exp_get_decl_var(sub_exp
));
647 for (ptr
= (char *) ret_val
; 0 < count
--; ptr
+= size
) {
651 sub_exp
->data
.func
->handler(&ele
, sub_exp
, (void *) &ptr
, frame
);
652 add_next_index_zval(return_value
, &ele
);
659 * set $ivar = to_array(dvar,
660 * $foo = to_int(d_foo),
661 * $bar = to_string(d_bar));
663 void psi_set_to_array(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*r_val
, struct psi_call_frame
*frame
)
665 struct psi_set_exp
*sub_exp
;
666 struct psi_decl_var
*var
;
670 array_init(return_value
);
672 var
= psi_set_exp_get_decl_var(set
);
673 ret_val
= deref_impl_val(r_val
, var
);
674 if ((intptr_t) ret_val
<= (intptr_t) 0) {
678 while (psi_plist_get(set
->inner
, i
++, &sub_exp
)) {
680 struct psi_decl_var
*dvar
= psi_set_exp_get_decl_var(sub_exp
);
681 struct psi_impl_var
*ivar
= psi_set_exp_get_impl_var(sub_exp
);
682 struct psi_call_frame_symbol
*sym
;
684 sym
= psi_call_frame_fetch_symbol(frame
, dvar
);
685 sym
->ptr
= ((char *) ret_val
) + dvar
->arg
->layout
->pos
;
688 psi_set_exp_exec_ex(sub_exp
, &ele
, sym
->ptr
, frame
);
689 add_assoc_zval_ex(return_value
, ivar
->name
->val
+ 1, ivar
->name
->len
- 1, &ele
);
694 * let dvar = count($ivar)
696 impl_val
*psi_let_count(impl_val
*tmp
, struct psi_decl_arg
*spec
, token_t impl_type
, impl_val
*ival
, zval
*zvalue
, void **to_free
)
698 return psi_val_intval(tmp
, psi_decl_type_get_real(spec
->type
)->type
, psi_zval_count(zvalue
));
702 * set $ivar = to_object(dvar)
704 void psi_set_to_object(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*r_val
, struct psi_call_frame
*frame
)
706 struct psi_decl_var
*var
= psi_set_exp_get_decl_var(set
);
707 impl_val
*ret_val
= deref_impl_val(r_val
, var
);
709 if ((intptr_t) ret_val
->ptr
> (intptr_t) 0) {
710 object_init_ex(return_value
, psi_object_get_class_entry());
711 PSI_OBJ(return_value
, NULL
)->data
= ret_val
->ptr
;
718 * let dvar = objval($ivar)
720 impl_val
*psi_let_objval(impl_val
*tmp
, struct psi_decl_arg
*spec
, token_t impl_type
, impl_val
*ival
, zval
*zvalue
, void **to_free
)
724 if (Z_TYPE_P(zvalue
) != IS_OBJECT
725 || !instanceof_function(Z_OBJCE_P(zvalue
), psi_object_get_class_entry())) {
729 obj
= PSI_OBJ(zvalue
, NULL
);
730 tmp
->ptr
= obj
->data
;