1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
/**
* Function.cpp
*
* Implementation for the function class
*
* @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
* @copyright 2013 Copernica BV
*/
#include "includes.h"
/**
* Set up namespace
*/
namespace Php {
/**
* Function that is called by the Zend engine every time that a function gets called
* @param ht
* @param return_value
* @param return_value_ptr
* @param this_ptr
* @param return_value_used
* @param tsrm_ls
* @return integer
*/
void Callable::invoke(INTERNAL_FUNCTION_PARAMETERS)
{
// find the function name
const char *name = get_active_function_name(TSRMLS_C);
// uncover the hidden pointer inside the function name
Callable *callable = HiddenPointer<Callable>(name);
// construct parameters
ParametersImpl params(this_ptr, ZEND_NUM_ARGS() TSRMLS_CC);
// the function could throw an exception
try
{
// get the result
Value result(callable->invoke(params));
// detach the zval (we don't want it to be destructed)
zval *val = result.detach();
// @todo php 5.6 has a RETVAL_ZVAL_FAST macro that can be used instead (and is faster)
// return a full copy of the zval, and do not destruct it
RETVAL_ZVAL(val, 1, 0);
}
catch (Exception &exception)
{
// process the exception
process(exception TSRMLS_CC);
}
}
/**
* Fill a function entry
*
* This method is called when the extension is registering itself, when the
* function or method introces himself
*
* @param entry Entry to be filled
* @param classname Optional class name
* @param flags Is this a public property?
*/
void Callable::initialize(zend_function_entry *entry, const char *classname, int flags) const
{
// fill the members of the entity, and hide a pointer to the current object in the name
entry->fname = (const char *)_ptr;
entry->handler = &Callable::invoke;
entry->arg_info = _argv;
entry->num_args = _argc;
entry->flags = flags;
// we should fill the first argument as well
initialize((zend_arg_info *)entry->arg_info, classname);
}
/**
* Fill a function entry
* @param info Info to be filled
* @param classname Optional classname
*/
void Callable::initialize(zend_arg_info *info, const char *classname) const
{
#if PHP_VERSION_ID >= 50400
// up until php 5.3, the first info object is filled with alternative information,
// later it is casted to a zend_internal_function object
auto *finfo = (zend_internal_function_info *)info;
// fill in all the members, note that return reference is false by default,
// because we do not support returning references in PHP-CPP, although Zend
// engine allows it. Inside the name we hide a pointer to the current object
finfo->_name = _ptr;
finfo->_name_len = ::strlen(_ptr);
finfo->_class_name = classname;
// number of required arguments, and the expected return type
finfo->required_num_args = _required;
finfo->_type_hint = (unsigned char)_return;
// we do not support return-by-reference
finfo->return_reference = false;
# if PHP_VERSION_ID >= 50600
// since php 5.6 there are _allow_null and _is_variadic properties. It's
// not exactly clear what they do (@todo find this out) so for now we set
// them to false
finfo->_allow_null = false;
finfo->_is_variadic = false;
# else
// passing by reference is not used (only for php 5.4 and php 5.5)
finfo->pass_rest_by_reference = false;
# endif
#else
// php 5.3 code
info->name = nullptr;
info->name_len = 0;
info->class_name = nullptr;
info->class_name_len = 0;
info->array_type_hint = false;
info->allow_null = false;
info->pass_by_reference = false;
info->return_reference = false;
info->required_num_args = _required;
#endif
}
/**
* End of namespace
*/
}
|