blob: b014bb1a71fc9c016e20741b685eaa313dc468e7 (
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
|
/**
* ObjectImpl.h
*
* Implementation class for Base objects that allow the objects to be stored
* in the Zend engine
*
* @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
* @copyright 2014 Copernica BV
*/
/**
* Set up namespace
*/
namespace Php {
/**
* Class definition
*/
class ObjectImpl
{
private:
/**
* Structure with a first element which is a zend_object, so that
* it can be casted to a zend_object
* @var MixedObject
*/
struct MixedObject
{
/**
* Pointer to ourselves
* @var ObjectImpl
*/
ObjectImpl *self;
/**
* The actual object MUST be the last member, because PHP uses hackish
* tricks for optimization (we allocate more memory than sizeof(MixedObject))
* @var zend_object
*/
zend_object php;
} *_mixed;
/**
* Pointer to the C++ implementation
* @var std::unique_ptr<Base>
*/
std::unique_ptr<Base> _object;
public:
/**
* Constructor
*
* This will create a new object in the Zend engine.
*
* @param entry Zend class entry
* @param handler Zend object handlers
* @param base C++ object that already exists
* @param refcount The initial refcount for the object
* @param tsrm_ls Optional threading data
*/
ObjectImpl(zend_class_entry *entry, Base *base, zend_object_handlers *handlers, int refcount TSRMLS_DC) :
_object(base)
{
// allocate a mixed object (for some reason this does not have to be deallocated)
_mixed = (MixedObject *)ecalloc(1, sizeof(MixedObject) + zend_object_properties_size(entry));
// copy properties to the mixed object
_mixed->php.ce = entry;
_mixed->self = this;
// initialize the object and its properties
zend_object_std_init (&_mixed->php, entry TSRMLS_CC);
object_properties_init(&_mixed->php, entry);
// install the handlers
_mixed->php.handlers = handlers;
// set the initial refcount (if it is different than one, because one is the default)
if (refcount != 1) php()->gc.refcount = refcount;
// the object may remember that we are its implementation object
base->_impl = this;
}
/**
* Destructor
*/
virtual ~ObjectImpl() = default;
/**
* Destruct the object
* @param tsrm_ls
*/
void destruct(TSRMLS_D)
{
// destruct the object
delete this;
}
/**
* The offset between the zend_object and the ObjectImpl
* in bytes. This can be used to find the other when only
* a pointer to one is available.
*
* @return The offset in bytes
*/
static constexpr size_t offset()
{
// calculate the offset in bytes
return offsetof(MixedObject, php);
}
/**
* Find the object based on a zval
* @param val Zval object
* @param tsrm_ls Optional pointer to thread info
* @return ObjectImpl
*/
static ObjectImpl *find(zval *val TSRMLS_DC)
{
// retrieve the zend_object from the zval and use it to find the ObjectImpl
return find(Z_OBJ_P(val));
}
/**
* Find the object based on a zend_object
* @param object Zend object pointer
* @return ObjectImpl
*/
static ObjectImpl *find(const zend_object *object)
{
// the zend_object is the last pointer in the struct so we have to subtract the
// correct number of bytes from the pointer to get at the address at which the
// actual ObjectImpl starts. to be able to actually perform this pointer arithmetic
// we must first cast the pointer to a char (void pointer arithmetic is not allowed!)
auto *mixed = (const MixedObject*)((char*)object - offset());
// done
return mixed->self;
}
/**
* Retrieve the base class of the original C++ object
* @return Base
*/
Base *object() const
{
return _object.get();
}
/**
* Pointer to the PHP object
* @return zend_object
*/
zend_object *php() const
{
return &_mixed->php;
}
};
/**
* End of namespace
*/
}
|