Skip to content

Commit 7fe9edc

Browse files
committed
Fix object constructor and destructor.
1 parent 6b39e99 commit 7fe9edc

File tree

7 files changed

+47
-34
lines changed

7 files changed

+47
-34
lines changed

examples/http-client/src/client.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ pub fn make_client_builder_class() -> DynamicClass<ClientBuilder> {
5252
let state = this.as_mut_state();
5353
let client = replace_and_get(state, ClientBuilder::new(), ClientBuilder::build)?;
5454
let mut object = ClassEntry::<Option<Client>>::from_globals(HTTP_CLIENT_CLASS_NAME)?
55-
.new_object_without_construct();
55+
.init_object()?;
5656
*object.as_mut_state() = Some(client);
5757
Ok::<_, HttpClientError>(object)
5858
},
@@ -81,7 +81,7 @@ pub fn make_client_class() -> DynamicClass<Option<Client>> {
8181
let request_builder = client.get(url);
8282
let mut object =
8383
ClassEntry::<Option<RequestBuilder>>::from_globals(REQUEST_BUILDER_CLASS_NAME)?
84-
.new_object_without_construct();
84+
.init_object()?;
8585
*object.as_mut_state() = Some(request_builder);
8686
Ok::<_, HttpClientError>(object)
8787
},
@@ -97,7 +97,7 @@ pub fn make_client_class() -> DynamicClass<Option<Client>> {
9797
let request_builder = client.post(url);
9898
let mut object =
9999
ClassEntry::<Option<RequestBuilder>>::from_globals(REQUEST_BUILDER_CLASS_NAME)?
100-
.new_object_without_construct();
100+
.init_object()?;
101101
*object.as_mut_state() = Some(request_builder);
102102
Ok::<_, HttpClientError>(object)
103103
},

examples/http-client/src/request.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ pub fn make_request_builder_class() -> DynamicClass<Option<RequestBuilder>> {
2323
|this, _arguments| {
2424
let state = this.as_mut_state();
2525
let response = replace_and_get(state, None, |builder| builder.unwrap().send())?;
26-
let mut object = ClassEntry::<Option<Response>>::from_globals(RESPONSE_CLASS_NAME)?
27-
.new_object_without_construct();
26+
let mut object =
27+
ClassEntry::<Option<Response>>::from_globals(RESPONSE_CLASS_NAME)?.init_object()?;
2828
*object.as_mut_state() = Some(response);
2929
Ok::<_, HttpClientError>(object)
3030
},

phper-sys/php_wrapper.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,10 @@ zend_object* (**phper_get_create_object(zend_class_entry *ce))(zend_class_entry
152152
return &ce->create_object;
153153
}
154154

155+
bool phper_object_init_ex(zval *arg, zend_class_entry *class_type) {
156+
return object_init_ex(arg, class_type) == SUCCESS;
157+
}
158+
155159
bool phper_call_user_function(HashTable *function_table, zval *object, zval *function_name, zval *retval_ptr, uint32_t param_count, zval params[]) {
156160
function_table = function_table;
157161
return call_user_function(function_table, object, function_name, retval_ptr, param_count, params) == SUCCESS;

phper-sys/php_wrapper.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ size_t phper_zend_object_properties_size(zend_class_entry *ce);
5151
void *phper_zend_object_alloc(size_t obj_size, zend_class_entry *ce);
5252

5353
zend_object* (**phper_get_create_object(zend_class_entry *ce))(zend_class_entry *class_type);
54+
bool phper_object_init_ex(zval *arg, zend_class_entry *class_type);
5455

5556
bool phper_call_user_function(HashTable *function_table, zval *object, zval *function_name, zval *retval_ptr, uint32_t param_count, zval params[]);
5657

phper/src/classes.rs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use crate::{
44
alloc::EBox,
55
arrays::Array,
6-
errors::{ClassNotFoundError, StateTypeError},
6+
errors::{ClassNotFoundError, InitializeObjectError, StateTypeError},
77
functions::{Argument, Function, FunctionEntity, FunctionEntry, Method},
88
objects::{ExtendObject, Object},
99
strings::ZendString,
@@ -16,7 +16,7 @@ use once_cell::sync::OnceCell;
1616
use std::{
1717
any::{Any, TypeId},
1818
marker::PhantomData,
19-
mem::{size_of, zeroed, ManuallyDrop},
19+
mem::{forget, size_of, zeroed, ManuallyDrop},
2020
os::raw::c_int,
2121
ptr::null_mut,
2222
sync::{
@@ -229,25 +229,25 @@ impl<T: 'static> ClassEntry<T> {
229229

230230
/// Create the object from class and call `__construct` with arguments.
231231
pub fn new_object(&self, arguments: &mut [Val]) -> crate::Result<EBox<Object<T>>> {
232-
unsafe {
233-
let ptr = self.as_ptr() as *mut _;
234-
let f = (*phper_get_create_object(ptr)).unwrap_or(zend_objects_new);
235-
let object = f(ptr);
236-
let mut object: EBox<Object<T>> = EBox::from_raw(object.cast());
237-
let _ = object.call_construct(arguments)?;
238-
Ok(object)
239-
}
232+
let mut object = self.init_object()?;
233+
object.call_construct(arguments)?;
234+
Ok(object)
240235
}
241236

242237
/// Create the object from class, without calling `__construct`, be careful when `__construct`
243238
/// is necessary.
244-
pub fn new_object_without_construct(&self) -> EBox<Object<T>> {
239+
pub fn init_object(&self) -> crate::Result<EBox<Object<T>>> {
245240
unsafe {
246241
let ptr = self.as_ptr() as *mut _;
247-
let f = (*phper_get_create_object(ptr)).unwrap_or(zend_objects_new);
248-
let object = f(ptr);
249-
let object: EBox<Object<T>> = EBox::from_raw(object.cast());
250-
object
242+
let mut val = Val::undef();
243+
if !phper_object_init_ex(val.as_mut_ptr(), ptr) {
244+
Err(InitializeObjectError::new(self.get_name().as_str()?.to_owned()).into())
245+
} else {
246+
let object = (*val.as_mut_ptr()).value.obj;
247+
forget(val);
248+
let object: EBox<Object<T>> = EBox::from_raw(object.cast());
249+
Ok(object)
250+
}
251251
}
252252
}
253253

phper/src/errors.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ pub enum Error {
7373
#[error(transparent)]
7474
#[throwable(transparent)]
7575
CallMethod(#[from] CallMethodError),
76+
77+
#[error(transparent)]
78+
#[throwable(transparent)]
79+
InitializeObject(#[from] InitializeObjectError),
7680
}
7781

7882
impl Error {
@@ -134,3 +138,11 @@ pub struct CallMethodError {
134138
class_name: String,
135139
method_name: String,
136140
}
141+
142+
#[derive(Debug, thiserror::Error, crate::Throwable, Constructor)]
143+
#[error("Cannot instantiate class {class_name}")]
144+
#[throwable_class("Error")]
145+
#[throwable_crate]
146+
pub struct InitializeObjectError {
147+
class_name: String,
148+
}

phper/src/objects.rs

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -184,20 +184,21 @@ impl<T: 'static> Object<T> {
184184
}
185185
}
186186

187-
pub(crate) fn call_construct(&mut self, arguments: &mut [Val]) -> crate::Result<Option<()>> {
187+
pub(crate) fn call_construct(&mut self, arguments: &mut [Val]) -> crate::Result<bool> {
188188
unsafe {
189-
(*self.inner.handlers)
190-
.get_constructor
191-
.and_then(|get_constructor| {
189+
match (*self.inner.handlers).get_constructor {
190+
Some(get_constructor) => {
192191
let f = get_constructor(self.as_ptr() as *mut _);
193192
if f.is_null() {
194-
None
193+
Ok(false)
195194
} else {
196195
let zend_fn = ZendFunction::from_mut_ptr(f);
197-
Some(zend_fn.call_method(self, arguments).map(|_| ()))
196+
zend_fn.call_method(self, arguments)?;
197+
Ok(true)
198198
}
199-
})
200-
.transpose()
199+
}
200+
None => Ok(false),
201+
}
201202
}
202203
}
203204
}
@@ -213,12 +214,7 @@ impl<T> EAllocatable for Object<T> {
213214
unsafe {
214215
(*ptr).inner.gc.refcount -= 1;
215216
if (*ptr).inner.gc.refcount == 0 {
216-
let handlers = (*ptr).inner.handlers;
217-
(*handlers).dtor_obj.unwrap()(ptr.cast());
218-
(*handlers).free_obj.unwrap()(ptr.cast());
219-
220-
// zend_objects_store_call_destructors(ptr.cast());
221-
// zend_objects_store_free_object_storage(ptr.cast(), true.into());
217+
zend_objects_store_del(ptr.cast());
222218
}
223219
}
224220
}

0 commit comments

Comments
 (0)