Skip to content

Commit afdac8e

Browse files
Add support for field and method properties (#69)
* Rough implementation of struct properties * Store properties hashtable once * Tidy up handler functions with exceptions * Add stub `get_properties` function for codegen structs * Remove nightly features * Revert storing properties Technically, the zend object _could_ move in memory, leaving dangling references in the properties hashtable. We will just build the hashtable when required. * Added `#[prop]` attribute * Add pointer type to zval, tidy up zend string * Add support for method properties * Add `#[getter]` and `#[setter]` attributes * Update documentation with method properties * Tidy up macros code * Remove string gc checks (done on PHP side) * Move `RegisteredClass` implementation to module, update docs * Fix read property `rv` segfault * Fixed doctests
1 parent aea8717 commit afdac8e

File tree

24 files changed

+1053
-316
lines changed

24 files changed

+1053
-316
lines changed

.github/workflows/build.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ jobs:
4848
EXT_PHP_RS_TEST:
4949
run: cargo build --release --features alloc,closure
5050
- name: Test guide examples
51+
env:
52+
CARGO_PKG_NAME: mdbook-tests
53+
CARGO_PKG_VERSION: 0.1.0
5154
run: |
5255
mdbook test guide -L target/release/deps
5356
- name: Test inline examples

build.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ const ALLOWED_BINDINGS: &[&str] = &[
252252
"IS_TYPE_REFCOUNTED",
253253
"IS_UNDEF",
254254
"IS_VOID",
255+
"IS_PTR",
255256
"MAY_BE_ANY",
256257
"MAY_BE_BOOL",
257258
"USING_ZTS",
@@ -316,4 +317,10 @@ const ALLOWED_BINDINGS: &[&str] = &[
316317
"_ZEND_TYPE_NAME_BIT",
317318
"zval_ptr_dtor",
318319
"zend_refcounted_h",
320+
"zend_is_true",
321+
"zend_object_std_dtor",
322+
"zend_std_read_property",
323+
"zend_std_write_property",
324+
"zend_std_get_properties",
325+
"zend_std_has_property",
319326
];

docsrs_bindings.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,37 @@ pub struct _zend_object_handlers {
760760
extern "C" {
761761
pub static std_object_handlers: zend_object_handlers;
762762
}
763+
extern "C" {
764+
pub fn zend_std_get_properties(object: *mut zend_object) -> *mut HashTable;
765+
}
766+
extern "C" {
767+
pub fn zend_std_read_property(
768+
object: *mut zend_object,
769+
member: *mut zend_string,
770+
type_: ::std::os::raw::c_int,
771+
cache_slot: *mut *mut ::std::os::raw::c_void,
772+
rv: *mut zval,
773+
) -> *mut zval;
774+
}
775+
extern "C" {
776+
pub fn zend_std_write_property(
777+
object: *mut zend_object,
778+
member: *mut zend_string,
779+
value: *mut zval,
780+
cache_slot: *mut *mut ::std::os::raw::c_void,
781+
) -> *mut zval;
782+
}
783+
extern "C" {
784+
pub fn zend_std_has_property(
785+
object: *mut zend_object,
786+
member: *mut zend_string,
787+
has_set_exists: ::std::os::raw::c_int,
788+
cache_slot: *mut *mut ::std::os::raw::c_void,
789+
) -> ::std::os::raw::c_int;
790+
}
791+
extern "C" {
792+
pub fn zend_is_true(op: *mut zval) -> ::std::os::raw::c_int;
793+
}
763794
pub type zend_op_array = _zend_op_array;
764795
pub type zend_op = _zend_op;
765796
#[repr(C)]
@@ -946,6 +977,9 @@ extern "C" {
946977
extern "C" {
947978
pub fn zend_objects_clone_members(new_object: *mut zend_object, old_object: *mut zend_object);
948979
}
980+
extern "C" {
981+
pub fn zend_object_std_dtor(object: *mut zend_object);
982+
}
949983
#[repr(C)]
950984
#[derive(Debug, Copy, Clone)]
951985
pub struct _zend_objects_store {

example/skel/src/lib.rs

Lines changed: 24 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -1,121 +1,39 @@
1-
mod allocator;
2-
3-
use ext_php_rs::{
4-
parse_args,
5-
php::{
6-
args::Arg,
7-
enums::DataType,
8-
exceptions::PhpException,
9-
execution_data::ExecutionData,
10-
function::FunctionBuilder,
11-
types::{
12-
array::OwnedHashTable,
13-
callable::Callable,
14-
closure::Closure,
15-
object::{ClassObject, ClassRef},
16-
zval::{FromZval, IntoZval, Zval},
17-
},
18-
},
19-
php_class,
20-
prelude::*,
21-
};
22-
23-
#[php_class]
24-
#[property(test = 0)]
25-
#[property(another = "Hello world")]
26-
#[derive(Default, Debug, Clone)]
27-
pub struct Test {
28-
pub test: String,
29-
}
30-
31-
#[php_function]
32-
pub fn take_test(test: &Test) -> String {
33-
test.test.clone()
34-
}
1+
use ext_php_rs::prelude::*;
352

363
#[php_class]
37-
#[derive(Default)]
38-
struct PhpFuture {
39-
then: Option<Callable<'static>>,
40-
}
41-
42-
#[php_impl]
43-
impl PhpFuture {
44-
pub fn then(&mut self, then: Callable<'static>) {
45-
self.then = Some(then);
46-
}
47-
48-
pub fn now(&self) -> Result<(), PhpException> {
49-
if let Some(then) = &self.then {
50-
then.try_call(vec![&"Hello"]).unwrap();
51-
Ok(())
52-
} else {
53-
Err(PhpException::default("No `then`".into()))
4+
struct TestClass {
5+
#[prop(rename = "Hello")]
6+
a: i32,
7+
#[prop]
8+
b: i64,
9+
#[prop]
10+
c: String,
11+
}
12+
13+
impl Default for TestClass {
14+
fn default() -> Self {
15+
Self {
16+
a: 100,
17+
b: 123,
18+
c: "Hello, world!".into(),
5419
}
5520
}
56-
57-
pub fn obj(&self) -> ClassObject<Test> {
58-
ClassObject::new(Test {
59-
test: "Hello world from class entry :)".into(),
60-
})
61-
}
62-
63-
pub fn return_self(&self) -> ClassRef<PhpFuture> {
64-
ClassRef::from_ref(self).unwrap()
65-
}
6621
}
6722

6823
#[php_impl]
69-
impl Test {
70-
pub fn set_str(&mut self, str: String) {
71-
self.test = str;
24+
impl TestClass {
25+
#[getter]
26+
fn get_test_name(&self) -> String {
27+
self.c.clone()
7228
}
7329

74-
pub fn get_str(&self) -> String {
75-
self.test.clone()
30+
#[setter]
31+
fn set_test_name(&mut self, c: String) {
32+
self.c = c;
7633
}
7734
}
7835

79-
#[php_function]
80-
pub fn get_closure() -> Closure {
81-
let mut x = 100;
82-
Closure::wrap(Box::new(move || {
83-
x += 5;
84-
format!("x: {}", x)
85-
}) as Box<dyn FnMut() -> String>)
86-
}
87-
88-
#[php_function]
89-
pub fn fn_once() -> Closure {
90-
let x = "Hello".to_string();
91-
Closure::wrap_once(Box::new(move || {
92-
println!("val here: {}", &x);
93-
x
94-
}) as Box<dyn FnOnce() -> String>)
95-
}
96-
97-
#[php_function]
98-
pub fn closure_get_string() -> Closure {
99-
// Return a closure which takes two integers and returns a string
100-
Closure::wrap(Box::new(|a, b| format!("A: {} B: {}", a, b)) as Box<dyn Fn(i32, i32) -> String>)
101-
}
102-
103-
#[php_function]
104-
pub fn closure_count() -> Closure {
105-
let mut count = 0i32;
106-
107-
Closure::wrap(Box::new(move |a: i32| {
108-
count += a;
109-
count
110-
}) as Box<dyn FnMut(i32) -> i32>)
111-
}
112-
11336
#[php_module]
11437
pub fn module(module: ModuleBuilder) -> ModuleBuilder {
115-
module.function(
116-
FunctionBuilder::new("test_zval", test_zval)
117-
.arg(Arg::new("test", DataType::Array))
118-
.build()
119-
.unwrap(),
120-
)
38+
module
12139
}

example/skel/test.php

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,2 @@
11
<?php
22

3-
<<<<<<< HEAD
4-
<<<<<<< HEAD
5-
<<<<<<< HEAD
6-
test_zval(['hello' => 'world']);
7-
=======
8-
test_zval();
9-
>>>>>>> 712aded56 (Call zval destructor when changing zval type and dropping)
10-
=======
11-
test_zval(['hello' => 'world']);
12-
>>>>>>> 3646da741 (Remove `ZendHashTable` wrapper)
13-
=======
14-
test_zval([]);
15-
>>>>>>> 7ba9ee9bf (Refactor `ZendString` into a borrowed and owned variant)
16-
//include 'vendor/autoload.php';
17-
18-
//$ext = new ReflectionExtension('skel');
19-
20-
//dd($ext);
21-
22-
//$x = fn_once();
23-
//$x();
24-
//$x();
25-
26-
//// $x = get_closure();
27-
28-
//// var_dump($x(5));

0 commit comments

Comments
 (0)