Skip to content

Commit 3ea6f0c

Browse files
Allow returning of object references (#55)
* Allow returning of object references `TYPE` is now also on `IntoZval` which means `FromZval` does not need to be implemented on return types * Clippy lints
1 parent 6abe209 commit 3ea6f0c

File tree

11 files changed

+156
-35
lines changed

11 files changed

+156
-35
lines changed

example/skel/src/allocator.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,22 @@ impl PhpAllocator {
1919

2020
unsafe impl GlobalAlloc for PhpAllocator {
2121
unsafe fn alloc(&self, layout: std::alloc::Layout) -> *mut u8 {
22-
_emalloc(
22+
let ptr = _emalloc(
2323
layout.size() as _,
2424
std::ptr::null_mut(),
2525
0,
2626
std::ptr::null_mut(),
2727
0,
28-
) as *mut u8
28+
) as *mut u8;
29+
30+
eprintln!("allocating {} bytes at {:?}", layout.size(), ptr);
31+
32+
ptr
2933
}
3034

31-
unsafe fn dealloc(&self, ptr: *mut u8, _: std::alloc::Layout) {
35+
unsafe fn dealloc(&self, ptr: *mut u8, layout: std::alloc::Layout) {
36+
eprintln!("deallocating {} bytes at {:?}", layout.size(), ptr);
37+
3238
_efree(
3339
ptr as *mut _,
3440
std::ptr::null_mut(),

example/skel/src/lib.rs

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,8 @@
11
mod allocator;
22

3-
use std::{collections::HashMap, convert::TryFrom, mem::MaybeUninit};
4-
53
use allocator::PhpAllocator;
64
use ext_php_rs::{
7-
call_user_func, info_table_end, info_table_row, info_table_start,
8-
php::{
9-
class::ClassEntry,
10-
exceptions::PhpException,
11-
module::ModuleEntry,
12-
types::{array::ZendHashTable, callable::Callable, zval::Zval},
13-
},
5+
php::{class::ClassEntry, exceptions::PhpException},
146
php_class,
157
prelude::*,
168
};
@@ -121,6 +113,27 @@ pub fn test_exception() -> Result<i32, PhpException<'static>> {
121113
))
122114
}
123115

116+
#[php_class]
117+
#[derive(Default)]
118+
pub struct Test {
119+
test: String,
120+
}
121+
122+
#[php_impl]
123+
impl Test {
124+
pub fn get(&mut self) -> &Test {
125+
self
126+
}
127+
128+
pub fn set_str(&mut self, str: String) {
129+
self.test = str;
130+
}
131+
132+
pub fn get_str(&self) -> String {
133+
self.test.clone()
134+
}
135+
}
136+
124137
#[php_module]
125138
pub fn module(module: ModuleBuilder) -> ModuleBuilder {
126139
// module.info_function(php_module_info)

example/skel/test.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,12 @@
22

33
include __DIR__.'/vendor/autoload.php';
44

5-
var_dump(test_str("Hello wordl"));
6-
# var_dump(test_exception());
5+
var_dump('program starting');
6+
$x = new Test();
7+
$x->set_str('Hello World');
8+
var_dump($x->get_str());
9+
var_dump($x->get());
10+
var_dump($x->get_str());
11+
// var_dump($x);
12+
var_dump('program done');
13+
// var_dump($x->get_str());

ext-php-rs-derive/src/function.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ impl Function {
418418

419419
// TODO allow reference returns?
420420
quote! {
421-
.returns(<#ty as ::ext_php_rs::php::types::zval::FromZval>::TYPE, false, #nullable)
421+
.returns(<#ty as ::ext_php_rs::php::types::zval::IntoZval>::TYPE, false, #nullable)
422422
}
423423
});
424424

ext-php-rs-derive/src/method.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ impl Method {
216216

217217
// TODO allow reference returns?
218218
quote! {
219-
.returns(<#ty as ::ext_php_rs::php::types::zval::FromZval>::TYPE, false, #nullable)
219+
.returns(<#ty as ::ext_php_rs::php::types::zval::IntoZval>::TYPE, false, #nullable)
220220
}
221221
});
222222

guide/src/types/index.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,6 @@ There is one special case - `Result<T, E>`, where T implements `IntoZval` and
2222
`E` implements `Into<PhpException>`. This can only be used as a function/method
2323
return type. If the error variant is encountered, `E` is converted into a
2424
`PhpException` and thrown.
25+
26+
For a type to be returnable, it must implement `IntoZval`, while for it to be
27+
valid as a parameter, it must implement `FromZval`.

src/php/args.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::convert::{TryFrom, TryInto};
55
use super::{
66
enums::DataType,
77
execution_data::ExecutionData,
8-
types::zval::{IntoZval, Zval},
8+
types::zval::{IntoZvalDyn, Zval},
99
};
1010

1111
use crate::{
@@ -94,7 +94,7 @@ impl<'a> Arg<'a> {
9494
/// # Parameters
9595
///
9696
/// * `params` - A list of parameters to call the function with.
97-
pub fn try_call(&self, params: Vec<&dyn IntoZval>) -> Result<Zval> {
97+
pub fn try_call(&self, params: Vec<&dyn IntoZvalDyn>) -> Result<Zval> {
9898
self.zval().ok_or(Error::Callable)?.try_call(params)
9999
}
100100
}

src/php/types/binary.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ impl<T: Pack> TryFrom<Zval> for Binary<T> {
6868
}
6969

7070
impl<T: Pack> IntoZval for Binary<T> {
71+
const TYPE: DataType = DataType::String;
72+
7173
fn set_zval(&self, zv: &mut Zval, _: bool) -> Result<()> {
7274
zv.set_binary(&self.0);
7375
Ok(())

src/php/types/callable.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use std::ops::Deref;
44

5-
use super::zval::{IntoZval, Zval};
5+
use super::zval::{IntoZvalDyn, Zval};
66
use crate::{
77
bindings::_call_user_function_impl,
88
errors::{Error, Result},
@@ -92,7 +92,7 @@ impl<'a> Callable<'a> {
9292
/// # Parameters
9393
///
9494
/// * `params` - A list of parameters to call the function with.
95-
pub fn try_call(&self, params: Vec<&dyn IntoZval>) -> Result<Zval> {
95+
pub fn try_call(&self, params: Vec<&dyn IntoZvalDyn>) -> Result<Zval> {
9696
if !self.0.is_callable() {
9797
return Err(Error::Callable);
9898
}

src/php/types/object.rs

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@ use crate::{
1818
ZEND_PROPERTY_ISSET,
1919
},
2020
errors::{Error, Result},
21-
php::{class::ClassEntry, execution_data::ExecutionData, types::string::ZendString},
21+
php::{
22+
class::ClassEntry, enums::DataType, execution_data::ExecutionData,
23+
types::string::ZendString,
24+
},
2225
};
2326

2427
use super::{
@@ -154,6 +157,11 @@ impl ZendObject {
154157
fn mut_ptr(&self) -> *mut Self {
155158
(self as *const Self) as *mut Self
156159
}
160+
161+
/// Increments the objects reference counter by 1.
162+
pub(crate) fn refcount_inc(&mut self) {
163+
self.gc.refcount += 1;
164+
}
157165
}
158166

159167
impl Debug for ZendObject {
@@ -179,7 +187,7 @@ impl Debug for ZendObject {
179187
///
180188
/// Implements a function `create_object` which is passed to a PHP class entry to instantiate the
181189
/// object that will represent an object.
182-
pub trait ZendObjectOverride {
190+
pub trait ZendObjectOverride: Default {
183191
/// Creates a new Zend object. Also allocates space for type T on which the trait is
184192
/// implemented on.
185193
///
@@ -201,6 +209,19 @@ pub trait ZendObjectOverride {
201209
fn set_class(ce: &'static ClassEntry);
202210
}
203211

212+
impl<T: ZendObjectOverride> IntoZval for &T {
213+
const TYPE: DataType = DataType::Object;
214+
215+
fn set_zval(&self, zv: &mut Zval, _: bool) -> Result<()> {
216+
unsafe {
217+
let obj = ZendClassObject::from_obj_ptr(*self).ok_or(Error::InvalidPointer)?;
218+
zv.set_object(&mut obj.std);
219+
}
220+
221+
Ok(())
222+
}
223+
}
224+
204225
/// A Zend class object which is allocated when a PHP
205226
/// class object is instantiated. Overrides the default
206227
/// handler when the user provides a type T of the struct
@@ -262,6 +283,20 @@ impl<T: Default> ZendClassObject<T> {
262283
ptr.as_mut()
263284
}
264285
}
286+
287+
/// Returns a reference to the [`ZendClassObject`] of a given object `T`.
288+
///
289+
/// # Parameters
290+
///
291+
/// * `obj` - The object to get the [`ZendClassObject`] for.
292+
///
293+
/// # Safety
294+
///
295+
/// Caller must guarantee that the given `obj` was created by Zend, which means that it
296+
/// is immediately followed by a [`zend_object`].
297+
pub(crate) unsafe fn from_obj_ptr(obj: &T) -> Option<&mut Self> {
298+
((obj as *const T) as *mut Self).as_mut()
299+
}
265300
}
266301

267302
impl<T: Default + Debug> Debug for ZendClassObject<T> {

0 commit comments

Comments
 (0)