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
139
140
141
142
143
144
145
146
147
148
149
150
151
|
/**
* 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 invoke_function(INTERNAL_FUNCTION_PARAMETERS)
{
// find the function name
const char *name = get_active_function_name(TSRMLS_C);
// uncover the hidden pointer inside the function name
Function *function = HiddenPointer<Function>(name);
// wrap the return value
Value result(return_value, true);
// construct parameters
Parameters params(this_ptr, ZEND_NUM_ARGS());
// the function could throw an exception
try
{
// get the result
result = function->invoke(params);
}
catch (Php::OrigException &exception)
{
// we caught an exception that was original thrown by PHP code, and not
// processed by C++ code, this means that we're going to restore this
// exception so that it can be further handled by PHP
exception.restore();
}
catch (Php::Exception &exception)
{
// an exception originally thrown by C++ should be passed on to PHP
zend_throw_exception(zend_exception_get_default(), (char*)exception.message().c_str(), 0 TSRMLS_CC);
}
}
/**
* Constructor
* @param name Name of the function
* @param min Min number of arguments
* @param max Max number of arguments
*/
Function::Function(const char *name, const std::initializer_list<Argument> &arguments) : _ptr(this, name)
{
// construct vector for arguments
_argc = arguments.size();
_argv = new zend_arg_info[_argc+1];
// counter
int i=1;
// loop through the arguments
for (auto it = arguments.begin(); it != arguments.end(); it++)
{
// fill the arg info
it->fill(&_argv[i++]);
}
// @todo find out number of required arguments
_required = _argc;
}
/**
* Destructor
*/
Function::~Function()
{
delete[] _argv;
}
/**
* 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 Function::fill(zend_function_entry *entry, const char *classname, MemberModifier flags) const
{
// fill the members of the entity, and hide a pointer to the current object in the name
entry->fname = _ptr;
entry->handler = invoke_function;
entry->arg_info = _argv;
entry->num_args = _argc;
entry->flags = flags;
// we should fill the first argument as well
#if PHP_VERSION_ID >= 50400
fill((zend_internal_function_info *)entry->arg_info, classname);
#endif
}
/**
* Fill a function entry
* @param info Info to be filled
* @param classname Optional classname
*/
#if PHP_VERSION_ID >= 50400
void Function::fill(zend_internal_function_info *info, const char *classname) const
{
// 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
info->_name = _ptr;
info->_name_len = _ptr.length();
info->_class_name = classname;
// number of required arguments, and the expected return type
info->required_num_args = _required;
info->_type_hint = _type;
// we do not support return-by-reference
info->return_reference = false;
// passing by reference is not used
info->pass_rest_by_reference = false;
}
#endif
/**
* End of namespace
*/
}
|