php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
com_wrapper.c
Go to the documentation of this file.
1/*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Author: Wez Furlong <wez@thebrainroom.com> |
14 +----------------------------------------------------------------------+
15 */
16
17/* This module exports a PHP object as a COM object by wrapping it
18 * using IDispatchEx */
19
20#ifdef HAVE_CONFIG_H
21#include <config.h>
22#endif
23
24#include "php.h"
25#include "php_ini.h"
26#include "ext/standard/info.h"
27#include "php_com_dotnet.h"
29
30typedef struct {
31 /* This first part MUST match the declaration
32 * of interface IDispatchEx */
33 CONST_VTBL struct IDispatchExVtbl *lpVtbl;
34
35 /* now the PHP stuff */
36
37 DWORD engine_thread; /* for sanity checking */
38 zval object; /* the object exported */
39 LONG refcount; /* COM reference count */
40
41 HashTable *dispid_to_name; /* keep track of dispid -> name mappings */
42 HashTable *name_to_dispid; /* keep track of name -> dispid mappings */
43
44 GUID sinkid; /* iid that we "implement" for event sinking */
46
47static void disp_destructor(php_dispatchex *disp);
48
49
50/* {{{ trace */
51static inline void trace(char *fmt, ...)
52{
53 va_list ap;
54 char buf[4096];
55
56 snprintf(buf, sizeof(buf), "T=%08lx ", GetCurrentThreadId());
57 OutputDebugString(buf);
58
59 va_start(ap, fmt);
60 vsnprintf(buf, sizeof(buf), fmt, ap);
61
62 OutputDebugString(buf);
63
64 va_end(ap);
65}
66/* }}} */
67
68#define FETCH_DISP(methname) \
69 php_dispatchex *disp = (php_dispatchex*)This; \
70 if (COMG(rshutdown_started)) { \
71 trace(" PHP Object:%p (name:unknown) %s\n", Z_OBJ(disp->object), methname); \
72 } else { \
73 trace(" PHP Object:%p (name:%s) %s\n", Z_OBJ(disp->object), ZSTR_VAL(Z_OBJCE(disp->object)->name), methname); \
74 } \
75 if (GetCurrentThreadId() != disp->engine_thread) { \
76 return RPC_E_WRONG_THREAD; \
77 }
78
79static HRESULT STDMETHODCALLTYPE disp_queryinterface(
80 IDispatchEx *This,
81 /* [in] */ REFIID riid,
82 /* [iid_is][out] */ void **ppvObject)
83{
84 FETCH_DISP("QueryInterface");
85
86 if (IsEqualGUID(&IID_IUnknown, riid) ||
87 IsEqualGUID(&IID_IDispatch, riid) ||
88 IsEqualGUID(&IID_IDispatchEx, riid) ||
89 IsEqualGUID(&disp->sinkid, riid)) {
90 *ppvObject = This;
91 InterlockedIncrement(&disp->refcount);
92 return S_OK;
93 }
94
95 *ppvObject = NULL;
96 return E_NOINTERFACE;
97}
98
99static ULONG STDMETHODCALLTYPE disp_addref(IDispatchEx *This)
100{
101 FETCH_DISP("AddRef");
102
103 return InterlockedIncrement(&disp->refcount);
104}
105
106static ULONG STDMETHODCALLTYPE disp_release(IDispatchEx *This)
107{
108 ULONG ret;
109 FETCH_DISP("Release");
110
111 ret = InterlockedDecrement(&disp->refcount);
112 trace("-- refcount now %lu\n", ret);
113 if (ret == 0) {
114 /* destroy it */
115 disp_destructor(disp);
116 }
117 return ret;
118}
119
120static HRESULT STDMETHODCALLTYPE disp_gettypeinfocount(
121 IDispatchEx *This,
122 /* [out] */ UINT *pctinfo)
123{
124 FETCH_DISP("GetTypeInfoCount");
125
126 *pctinfo = 0;
127 return S_OK;
128}
129
130static HRESULT STDMETHODCALLTYPE disp_gettypeinfo(
131 IDispatchEx *This,
132 /* [in] */ UINT iTInfo,
133 /* [in] */ LCID lcid,
134 /* [out] */ ITypeInfo **ppTInfo)
135{
136 FETCH_DISP("GetTypeInfo");
137
138 *ppTInfo = NULL;
139 return DISP_E_BADINDEX;
140}
141
142static HRESULT STDMETHODCALLTYPE disp_getidsofnames(
143 IDispatchEx *This,
144 /* [in] */ REFIID riid,
145 /* [size_is][in] */ LPOLESTR *rgszNames,
146 /* [in] */ UINT cNames,
147 /* [in] */ LCID lcid,
148 /* [size_is][out] */ DISPID *rgDispId)
149{
150 UINT i;
151 HRESULT ret = S_OK;
152 FETCH_DISP("GetIDsOfNames");
153
154 for (i = 0; i < cNames; i++) {
156 zval *tmp;
157
159
160 /* Lookup the name in the hash */
161 if ((tmp = zend_hash_find(disp->name_to_dispid, name)) == NULL) {
162 ret = DISP_E_UNKNOWNNAME;
163 rgDispId[i] = 0;
164 } else {
165 rgDispId[i] = (DISPID)Z_LVAL_P(tmp);
166 }
167
168 zend_string_release_ex(name, /* persistent */ false);
169
170 }
171
172 return ret;
173}
174
175static HRESULT STDMETHODCALLTYPE disp_invoke(
176 IDispatchEx *This,
177 /* [in] */ DISPID dispIdMember,
178 /* [in] */ REFIID riid,
179 /* [in] */ LCID lcid,
180 /* [in] */ WORD wFlags,
181 /* [out][in] */ DISPPARAMS *pDispParams,
182 /* [out] */ VARIANT *pVarResult,
183 /* [out] */ EXCEPINFO *pExcepInfo,
184 /* [out] */ UINT *puArgErr)
185{
186 return This->lpVtbl->InvokeEx(This, dispIdMember,
187 lcid, wFlags, pDispParams,
188 pVarResult, pExcepInfo, NULL);
189}
190
191static HRESULT STDMETHODCALLTYPE disp_getdispid(
192 IDispatchEx *This,
193 /* [in] */ BSTR bstrName,
194 /* [in] */ DWORD grfdex,
195 /* [out] */ DISPID *pid)
196{
197 HRESULT ret = DISP_E_UNKNOWNNAME;
199 zval *tmp;
200 FETCH_DISP("GetDispID");
201
203
204 trace("Looking for %s, namelen=%lu in %p\n", ZSTR_VAL(name), ZSTR_LEN(name), disp->name_to_dispid);
205
206 /* Lookup the name in the hash */
207 if ((tmp = zend_hash_find(disp->name_to_dispid, name)) != NULL) {
208 trace("found it\n");
209 *pid = (DISPID)Z_LVAL_P(tmp);
210 ret = S_OK;
211 }
212
213 zend_string_release_ex(name, /* persistent */ false);
214
215 return ret;
216}
217
218static HRESULT STDMETHODCALLTYPE disp_invokeex(
219 IDispatchEx *This,
220 /* [in] */ DISPID id,
221 /* [in] */ LCID lcid,
222 /* [in] */ WORD wFlags,
223 /* [in] */ DISPPARAMS *pdp,
224 /* [out] */ VARIANT *pvarRes,
225 /* [out] */ EXCEPINFO *pei,
226 /* [unique][in] */ IServiceProvider *pspCaller)
227{
228 zval *name;
229 UINT i;
230 zval rv, *retval = NULL;
231 zval *params = NULL;
232 HRESULT ret = DISP_E_MEMBERNOTFOUND;
233 FETCH_DISP("InvokeEx");
234
235 if (NULL != (name = zend_hash_index_find(disp->dispid_to_name, id))) {
236 /* TODO: add support for overloaded objects */
237
238 trace("-- Invoke: %ld %20s [%lu] flags=%08x args=%u\n", id, Z_STRVAL_P(name), Z_STRLEN_P(name), wFlags, pdp->cArgs);
239
240 /* convert args into zvals.
241 * Args are in reverse order */
242 if (pdp->cArgs) {
243 params = (zval *)safe_emalloc(sizeof(zval), pdp->cArgs, 0);
244 for (i = 0; i < pdp->cArgs; i++) {
245 VARIANT *arg;
246
247 arg = &pdp->rgvarg[ pdp->cArgs - 1 - i];
248
249 trace("alloc zval for arg %u VT=%08x\n", i, V_VT(arg));
250
251 php_com_wrap_variant(&params[i], arg, COMG(code_page));
252 }
253 }
254
255 trace("arguments processed, prepare to do some work\n");
256
257 /* TODO: if PHP raises an exception here, we should catch it
258 * and expose it as a COM exception */
259
260 if (wFlags & DISPATCH_PROPERTYGET) {
261 retval = zend_read_property(Z_OBJCE(disp->object), Z_OBJ(disp->object), Z_STRVAL_P(name), Z_STRLEN_P(name)+1, 1, &rv);
262 } else if (wFlags & DISPATCH_PROPERTYPUT) {
263 zend_update_property(Z_OBJCE(disp->object), Z_OBJ(disp->object), Z_STRVAL_P(name), Z_STRLEN_P(name), &params[0]);
264 } else if (wFlags & DISPATCH_METHOD) {
265 zend_try {
266 retval = &rv;
267 if (SUCCESS == call_user_function(NULL, &disp->object, name,
268 retval, pdp->cArgs, params)) {
269 ret = S_OK;
270 trace("function called ok\n");
271
272 /* Copy any modified values to callers copy of variant*/
273 for (i = 0; i < pdp->cArgs; i++) {
274 php_com_dotnet_object *obj = CDNO_FETCH(&params[i]);
275 VARIANT *srcvar = &obj->v;
276 VARIANT *dstvar = &pdp->rgvarg[ pdp->cArgs - 1 - i];
277 if ((V_VT(dstvar) & VT_BYREF) && obj->modified ) {
278 trace("percolate modified value for arg %u VT=%08x\n", i, V_VT(dstvar));
279 php_com_copy_variant(dstvar, srcvar);
280 }
281 }
282 } else {
283 trace("failed to call func\n");
284 ret = DISP_E_EXCEPTION;
285 }
286 } zend_catch {
287 trace("something blew up\n");
288 ret = DISP_E_EXCEPTION;
289 } zend_end_try();
290 } else {
291 trace("Don't know how to handle this invocation %08x\n", wFlags);
292 }
293
294 /* release arguments */
295 if (params) {
296 for (i = 0; i < pdp->cArgs; i++) {
297 zval_ptr_dtor(&params[i]);
298 }
299 efree(params);
300 }
301
302 /* return value */
303 if (retval) {
304 if (pvarRes) {
305 VariantInit(pvarRes);
307 }
309 } else if (pvarRes) {
310 VariantInit(pvarRes);
311 }
312
313 } else {
314 trace("InvokeEx: I don't support DISPID=%ld\n", id);
315 }
316
317 return ret;
318}
319
320static HRESULT STDMETHODCALLTYPE disp_deletememberbyname(
321 IDispatchEx *This,
322 /* [in] */ BSTR bstrName,
323 /* [in] */ DWORD grfdex)
324{
325 FETCH_DISP("DeleteMemberByName");
326
327 /* TODO: unset */
328
329 return S_FALSE;
330}
331
332static HRESULT STDMETHODCALLTYPE disp_deletememberbydispid(
333 IDispatchEx *This,
334 /* [in] */ DISPID id)
335{
336 FETCH_DISP("DeleteMemberByDispID");
337
338 /* TODO: unset */
339
340 return S_FALSE;
341}
342
343static HRESULT STDMETHODCALLTYPE disp_getmemberproperties(
344 IDispatchEx *This,
345 /* [in] */ DISPID id,
346 /* [in] */ DWORD grfdexFetch,
347 /* [out] */ DWORD *pgrfdex)
348{
349 FETCH_DISP("GetMemberProperties");
350
351 return DISP_E_UNKNOWNNAME;
352}
353
354static HRESULT STDMETHODCALLTYPE disp_getmembername(
355 IDispatchEx *This,
356 /* [in] */ DISPID id,
357 /* [out] */ BSTR *pbstrName)
358{
359 zval *name;
360 FETCH_DISP("GetMemberName");
361
362 if (NULL != (name = zend_hash_index_find(disp->dispid_to_name, id))) {
364 *pbstrName = SysAllocString(olestr);
365 efree(olestr);
366 return S_OK;
367 } else {
368 return DISP_E_UNKNOWNNAME;
369 }
370}
371
372static HRESULT STDMETHODCALLTYPE disp_getnextdispid(
373 IDispatchEx *This,
374 /* [in] */ DWORD grfdex,
375 /* [in] */ DISPID id,
376 /* [out] */ DISPID *pid)
377{
378 zend_ulong next = id+1;
379 FETCH_DISP("GetNextDispID");
380
381 while(!zend_hash_index_exists(disp->dispid_to_name, next))
382 next++;
383
384 if (zend_hash_index_exists(disp->dispid_to_name, next)) {
385 *pid = next;
386 return S_OK;
387 }
388 return S_FALSE;
389}
390
391static HRESULT STDMETHODCALLTYPE disp_getnamespaceparent(
392 IDispatchEx *This,
393 /* [out] */ IUnknown **ppunk)
394{
395 FETCH_DISP("GetNameSpaceParent");
396
397 *ppunk = NULL;
398 return E_NOTIMPL;
399}
400
401static struct IDispatchExVtbl php_dispatch_vtbl = {
402 disp_queryinterface,
403 disp_addref,
404 disp_release,
405 disp_gettypeinfocount,
406 disp_gettypeinfo,
407 disp_getidsofnames,
408 disp_invoke,
409 disp_getdispid,
410 disp_invokeex,
411 disp_deletememberbyname,
412 disp_deletememberbydispid,
413 disp_getmemberproperties,
414 disp_getmembername,
415 disp_getnextdispid,
416 disp_getnamespaceparent
417};
418
419
420/* enumerate functions and properties of the object and assign
421 * dispatch ids */
422static void generate_dispids(php_dispatchex *disp)
423{
426 zval *tmp, tmp2;
427 int keytype;
428 zend_ulong pid;
429
430 if (disp->dispid_to_name == NULL) {
435 }
436
437 /* properties */
438 if (Z_OBJPROP(disp->object)) {
440 while (HASH_KEY_NON_EXISTENT != (keytype =
442 &pid, &pos))) {
443 char namebuf[32];
444 if (keytype == HASH_KEY_IS_LONG) {
445 snprintf(namebuf, sizeof(namebuf), ZEND_ULONG_FMT, pid);
446 name = zend_string_init(namebuf, strlen(namebuf), 0);
447 } else {
448 zend_string_addref(name);
449 }
450
452
453 /* Find the existing id */
454 if ((tmp = zend_hash_find(disp->name_to_dispid, name)) != NULL) {
456 continue;
457 }
458
459 /* add the mappings */
460 ZVAL_STR_COPY(&tmp2, name);
461 pid = zend_hash_next_free_element(disp->dispid_to_name);
462 zend_hash_index_update(disp->dispid_to_name, pid, &tmp2);
463
464 ZVAL_LONG(&tmp2, pid);
465 zend_hash_update(disp->name_to_dispid, name, &tmp2);
466
468 }
469 }
470
471 /* functions */
472 if (Z_OBJCE(disp->object)) {
473 zend_hash_internal_pointer_reset_ex(&Z_OBJCE(disp->object)->function_table, &pos);
474 while (HASH_KEY_NON_EXISTENT != (keytype =
475 zend_hash_get_current_key_ex(&Z_OBJCE(disp->object)->function_table,
476 &name, &pid, &pos))) {
477
478 char namebuf[32];
479 if (keytype == HASH_KEY_IS_LONG) {
480 snprintf(namebuf, sizeof(namebuf), ZEND_ULONG_FMT, pid);
481 name = zend_string_init(namebuf, strlen(namebuf), 0);
482 } else {
483 zend_string_addref(name);
484 }
485
486 zend_hash_move_forward_ex(&Z_OBJCE(disp->object)->function_table, &pos);
487
488 /* Find the existing id */
489 if ((tmp = zend_hash_find(disp->name_to_dispid, name)) != NULL) {
491 continue;
492 }
493
494 /* add the mappings */
495 ZVAL_STR_COPY(&tmp2, name);
496 pid = zend_hash_next_free_element(disp->dispid_to_name);
497 zend_hash_index_update(disp->dispid_to_name, pid, &tmp2);
498
499 ZVAL_LONG(&tmp2, pid);
500 zend_hash_update(disp->name_to_dispid, name, &tmp2);
501
503 }
504 }
505}
506
507static php_dispatchex *disp_constructor(zval *object)
508{
509 php_dispatchex *disp = (php_dispatchex*)CoTaskMemAlloc(sizeof(php_dispatchex));
510
511 trace("constructing a COM wrapper for PHP object %p (%s)\n", object, ZSTR_VAL(Z_OBJCE_P(object)->name));
512
513 if (disp == NULL)
514 return NULL;
515
516 memset(disp, 0, sizeof(php_dispatchex));
517
518 disp->engine_thread = GetCurrentThreadId();
519 disp->lpVtbl = &php_dispatch_vtbl;
520 disp->refcount = 1;
521
522
523 if (object) {
524 ZVAL_COPY(&disp->object, object);
525 } else {
526 ZVAL_UNDEF(&disp->object);
527 }
528
529 return disp;
530}
531
532static void disp_destructor(php_dispatchex *disp)
533{
538
539 zval_ptr_dtor(&disp->object);
540
541 CoTaskMemFree(disp);
542}
543
545 HashTable *id_to_name)
546{
547 php_dispatchex *disp = disp_constructor(val);
550 zval tmp, *ntmp;
551 int keytype;
552 zend_ulong pid;
553
554 disp->dispid_to_name = id_to_name;
555
556 memcpy(&disp->sinkid, sinkid, sizeof(disp->sinkid));
557
558 /* build up the reverse mapping */
561
563 while (HASH_KEY_NON_EXISTENT != (keytype =
564 zend_hash_get_current_key_ex(id_to_name, &name, &pid, &pos))) {
565
566 if (keytype == HASH_KEY_IS_LONG) {
567
568 ntmp = zend_hash_get_current_data_ex(id_to_name, &pos);
569
570 ZVAL_LONG(&tmp, pid);
571 zend_hash_update(disp->name_to_dispid, Z_STR_P(ntmp), &tmp);
572 }
573
574 zend_hash_move_forward_ex(id_to_name, &pos);
575 }
576
577 return (IDispatch*)disp;
578}
579
581{
582 php_dispatchex *disp = NULL;
583
584 if (Z_TYPE_P(val) != IS_OBJECT) {
585 return NULL;
586 }
587
588 if (php_com_is_valid_object(val)) {
589 /* pass back its IDispatch directly */
591
592 if (obj == NULL)
593 return NULL;
594
595 if (V_VT(&obj->v) == VT_DISPATCH && V_DISPATCH(&obj->v)) {
596 IDispatch_AddRef(V_DISPATCH(&obj->v));
597 return V_DISPATCH(&obj->v);
598 }
599
600 return NULL;
601 }
602
603 disp = disp_constructor(val);
604 generate_dispids(disp);
605
606 return (IDispatch*)disp;
607}
const VT_BYREF
const DISP_E_BADINDEX
const VT_DISPATCH
PHP_COM_DOTNET_API void php_com_wrap_variant(zval *z, VARIANT *v, int codepage)
Definition com_misc.c:67
PHP_COM_DOTNET_API zend_string * php_com_olestring_to_string(OLECHAR *olestring, int codepage)
Definition com_olechar.c:70
PHP_COM_DOTNET_API OLECHAR * php_com_string_to_olestring(const char *string, size_t string_len, int codepage)
Definition com_olechar.c:29
PHP_COM_DOTNET_API void php_com_variant_from_zval(VARIANT *v, zval *z, int codepage)
PHP_COM_DOTNET_API zend_result php_com_copy_variant(VARIANT *dstvar, VARIANT *srcvar)
PHP_COM_DOTNET_API IDispatch * php_com_wrapper_export(zval *val)
PHP_COM_DOTNET_API IDispatch * php_com_wrapper_export_as_sink(zval *val, GUID *sinkid, HashTable *id_to_name)
#define FETCH_DISP(methname)
Definition com_wrapper.c:68
#define WORD
Definition exif.c:1759
#define DWORD
Definition exif.c:1762
memcpy(ptr1, ptr2, size)
zval * arg
Definition ffi.c:3975
memset(ptr, 0, type->size)
zval * val
Definition ffi.c:4262
zend_ffi_ctype_name_buf buf
Definition ffi.c:4685
#define NULL
Definition gdcache.h:45
#define SUCCESS
Definition hash_sha3.c:261
#define next(ls)
Definition minilua.c:2661
#define COMG(v)
int code_page
#define PHP_COM_DOTNET_API
#define CDNO_FETCH(zv)
struct _php_com_dotnet_object php_com_dotnet_object
unsigned const char * pos
Definition php_ffi.h:52
zval rv
Definition session.c:1024
#define vsnprintf
Definition snprintf.h:104
DWORD engine_thread
Definition com_wrapper.c:37
CONST_VTBL struct IDispatchExVtbl * lpVtbl
Definition com_wrapper.c:33
HashTable * name_to_dispid
Definition com_wrapper.c:42
HashTable * dispid_to_name
Definition com_wrapper.c:41
#define zend_catch
Definition zend.h:277
#define zend_try
Definition zend.h:270
#define zend_end_try()
Definition zend.h:280
ZEND_API zval * zend_read_property(zend_class_entry *scope, zend_object *object, const char *name, size_t name_length, bool silent, zval *rv)
Definition zend_API.c:5201
ZEND_API void zend_update_property(zend_class_entry *scope, zend_object *object, const char *name, size_t name_length, zval *value)
Definition zend_API.c:4991
#define call_user_function(function_table, object, function_name, retval_ptr, param_count, params)
Definition zend_API.h:687
#define efree(ptr)
Definition zend_alloc.h:155
#define FREE_HASHTABLE(ht)
Definition zend_alloc.h:234
#define safe_emalloc(nmemb, size, offset)
Definition zend_alloc.h:154
#define ALLOC_HASHTABLE(ht)
Definition zend_alloc.h:231
struct _zval_struct zval
strlen(string $string)
zend_string_release_ex(func->internal_function.function_name, 0)
#define snprintf
ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht)
Definition zend_hash.c:1727
ZEND_API zend_result ZEND_FASTCALL zend_hash_move_forward_ex(HashTable *ht, HashPosition *pos)
Definition zend_hash.c:2773
ZEND_API int ZEND_FASTCALL zend_hash_get_current_key_ex(const HashTable *ht, zend_string **str_index, zend_ulong *num_index, const HashPosition *pos)
Definition zend_hash.c:2846
ZEND_API void ZEND_FASTCALL zend_hash_internal_pointer_reset_ex(HashTable *ht, HashPosition *pos)
Definition zend_hash.c:2733
ZEND_API zval *ZEND_FASTCALL zend_hash_get_current_data_ex(HashTable *ht, HashPosition *pos)
Definition zend_hash.c:2915
ZEND_API zval *ZEND_FASTCALL zend_hash_index_update(HashTable *ht, zend_ulong h, zval *pData)
Definition zend_hash.c:1219
ZEND_API zval *ZEND_FASTCALL zend_hash_update(HashTable *ht, zend_string *key, zval *pData)
Definition zend_hash.c:997
ZEND_API zval *ZEND_FASTCALL zend_hash_find(const HashTable *ht, zend_string *key)
Definition zend_hash.c:2668
ZEND_API zval *ZEND_FASTCALL zend_hash_index_find(const HashTable *ht, zend_ulong h)
Definition zend_hash.c:2701
#define zend_hash_init(ht, nSize, pHashFunction, pDestructor, persistent)
Definition zend_hash.h:108
#define HASH_KEY_NON_EXISTENT
Definition zend_hash.h:31
#define HASH_KEY_IS_LONG
Definition zend_hash.h:30
#define ZEND_ULONG_FMT
Definition zend_long.h:88
uint32_t zend_ulong
Definition zend_long.h:43
struct _zend_string zend_string
#define ZSTR_VAL(zstr)
Definition zend_string.h:68
#define ZSTR_LEN(zstr)
Definition zend_string.h:69
#define Z_TYPE_P(zval_p)
Definition zend_types.h:660
#define ZVAL_UNDEF(z)
#define Z_STRVAL_P(zval_p)
Definition zend_types.h:975
#define ZVAL_LONG(z, l)
#define ZVAL_STR_COPY(z, s)
struct _zend_array HashTable
Definition zend_types.h:386
#define Z_STR_P(zval_p)
Definition zend_types.h:972
#define Z_STRLEN_P(zval_p)
Definition zend_types.h:978
#define Z_OBJCE_P(zval_p)
#define IS_OBJECT
Definition zend_types.h:608
#define ZVAL_COPY(z, v)
uint32_t HashPosition
Definition zend_types.h:548
#define Z_OBJPROP(zval)
#define Z_LVAL_P(zval_p)
Definition zend_types.h:966
#define Z_OBJCE(zval)
#define Z_OBJ(zval)
Definition zend_types.h:989
ZEND_API void zval_ptr_dtor(zval *zval_ptr)
#define ZVAL_PTR_DTOR
zval retval
zend_string * name
zval * ret