blob: 0a79b971c1eeca9daa8b6a8477c07c78897d78fd (
plain)
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
|
/**
* Opcodes.h
*
* Class represents a set of opcodes of a PHP script that can be executed. This
* is an internal file that you normally do not have to instantiate yourself.
* Better use the Php::Script of Php::File classes.
*
* @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
* @copyright 2014 Copernica BV
*/
/**
* Forward declarations
*/
struct _zend_op_array;
/**
* Namespace
*/
namespace Php {
/**
* Class definition
*/
class Opcodes
{
public:
/**
* Constructor
* @param opcodes
*/
Opcodes(struct _zend_op_array *opcodes TSRMLS_DC) : _opcodes(opcodes)
{
#ifdef ZTS
// copy tsrm_ls param
this->tsrm_ls = tsrm_ls;
#endif
}
/**
* Destructor
*/
virtual ~Opcodes()
{
// leap out if opcodes were not valid
if (!_opcodes) return;
// clean up opcodes
destroy_op_array(_opcodes TSRMLS_CC);
efree(_opcodes);
}
/**
* Are the opcodes valid?
* @return bool
*/
bool valid() const
{
return _opcodes != nullptr;
}
/**
* Execute the opcodes
* @return Value
*/
Value execute() const
{
// if the script could not be compiled, we return null
if (!_opcodes) return nullptr;
// pointer that is going to hold the return value of the script
zval retval;
// initialize to null
ZVAL_NULL(&retval);
// the zend engine is probably already busy processing opcodes, so we store
// the current execute state before we're going to switch the runtime to
// our own set of opcodes
ExecuteState execState(0 TSRMLS_CC);
// old execute state has been saved (and will automatically be restored when
// the oldstate is destructed), so we can now safely overwrite all the settings
CG(active_op_array) = _opcodes;
EG(no_extensions) = 1;
if (!EG(current_execute_data)->symbol_table) zend_rebuild_symbol_table(TSRMLS_C);
// the current exception
auto *oldException = EG(exception);
// execute the code
zend_execute(_opcodes, &retval TSRMLS_CC);
// was an exception thrown inside the eval()'ed code? In that case we
// throw a C++ new exception to give the C++ code the chance to catch it
if (oldException != EG(exception) && EG(exception)) throw OrigException(EG(exception) TSRMLS_CC);
// we're ready if there is no return value
if (ZVAL_IS_NULL(&retval)) return nullptr;
// wrap the return value
Value result(&retval);
// copy the pointer into a value object, and return that
return result;
}
private:
/**
* The opcodes
* @var zend_op_array
*/
struct _zend_op_array *_opcodes;
#ifdef ZTS
/**
* When in thread safety mode, we also keep track of the TSRM_LS var
* @var void***
*/
void ***tsrm_ls;
#endif
};
/**
* End of namespace
*/
}
|