Skip to content

Commit 243efec

Browse files
authored
Adapt to PHP 8.2. (#86)
1 parent 3b685a4 commit 243efec

File tree

9 files changed

+75
-56
lines changed

9 files changed

+75
-56
lines changed

.github/workflows/ci.yml

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ jobs:
5353
- "7.4"
5454
- "8.0"
5555
- "8.1"
56+
- "8.2"
5657

5758
runs-on: ${{ matrix.os }}
5859
steps:

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ The framework that allows us to write PHP extensions using pure and safe Rust wh
3838
- [x] 7.4
3939
- [x] 8.0
4040
- [x] 8.1
41+
- [x] 8.2
4142
- **mode**
4243
- [x] nts
4344
- [ ] zts

phper-doc/doc/_05_internal_types/_02_z_arr/index.md

+9-3
Original file line numberDiff line numberDiff line change
@@ -41,18 +41,24 @@ let _i = arr.get("10");
4141
arr.remove("foo");
4242
```
4343

44-
`ZArr` can be iterated by `iter()`.
44+
`ZArr` can be iterated by `for_each()`.
4545

4646
```rust,no_run
4747
use phper::arrays::ZArray;
4848
use phper::values::ZVal;
4949
5050
let arr = ZArray::new();
5151
52-
for (_k, _v) in arr.iter() {
53-
}
52+
53+
arr.for_each(|k, v| {
54+
dbg!(k, v);
55+
});
5456
```
5557

58+
*I used to provide the `iter()` method for `ZArr`, and let `Iter` implement
59+
`Iterator`, but if using the PHP stable macro `ZEND_HASH_FOREACH_KEY_VAL`, it is a
60+
bit difficult to provide `iter`, so it is deleted.*;
61+
5662
`ZArr` implements `ToOwned`, can upgrade to `ZArray` by value copy via
5763
`zend_array_dup`.
5864

phper-sys/build.rs

+2
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ fn main() {
4242
let mut builder = Builder::default()
4343
.header("php_wrapper.c")
4444
.allowlist_file("php_wrapper\\.c")
45+
// Block the `zend_ini_parse_quantity` because it's document causes the doc test to fail.
46+
.blocklist_function("zend_ini_parse_quantity")
4547
.clang_args(&includes)
4648
.derive_default(true);
4749

phper-sys/php_wrapper.c

+18-2
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,22 @@ uint32_t phper_zend_num_args(const zend_execute_data *execute_data) {
365365
return ZEND_NUM_ARGS();
366366
}
367367

368-
zend_bool phper_instanceof_function(const zend_class_entry *instance_ce, const zend_class_entry *ce) {
369-
return instanceof_function(instance_ce, ce);
368+
bool phper_instanceof_function(const zend_class_entry *instance_ce, const zend_class_entry *ce) {
369+
return instanceof_function(instance_ce, ce) != 0;
370+
}
371+
372+
bool phper_zend_get_parameters_array_ex(uint32_t param_count, zval *argument_array) {
373+
return zend_get_parameters_array_ex(param_count, argument_array) != 0;
374+
}
375+
376+
typedef void (*phper_foreach_func_arg_t)(zend_ulong idx, zend_string *key, zval *val, void *argument);
377+
378+
void phper_zend_hash_foreach_key_val(zend_array *array, phper_foreach_func_arg_t f, void *argument) {
379+
zend_ulong idx;
380+
zend_string *key;
381+
zval *val;
382+
383+
ZEND_HASH_FOREACH_KEY_VAL(array, idx, key, val) {
384+
f(idx, key, val, argument);
385+
} ZEND_HASH_FOREACH_END();
370386
}

phper/src/arrays.rs

+20-46
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use derive_more::From;
1515
use std::{
1616
borrow::Borrow,
1717
convert::TryInto,
18+
ffi::c_void,
1819
marker::PhantomData,
1920
mem::{forget, ManuallyDrop},
2021
ops::{Deref, DerefMut},
@@ -103,7 +104,7 @@ impl ZArr {
103104
self.len() == 0
104105
}
105106

106-
// Get items length.
107+
/// Get items length.
107108
#[inline]
108109
pub fn len(&mut self) -> usize {
109110
unsafe { zend_array_count(self.as_mut_ptr()).try_into().unwrap() }
@@ -243,10 +244,11 @@ impl ZArr {
243244
}
244245
}
245246

246-
pub fn iter(&self) -> Iter<'_> {
247-
Iter {
248-
index: 0,
249-
array: self,
247+
pub fn for_each<'a>(&self, f: impl FnMut(IterKey<'a>, &'a ZVal)) {
248+
let mut f: Box<dyn FnMut(IterKey<'a>, &'a ZVal)> = Box::new(f);
249+
let f = &mut f as *mut Box<_> as *mut c_void;
250+
unsafe {
251+
phper_zend_hash_foreach_key_val(self.as_ptr() as *mut _, Some(for_each_callback), f);
250252
}
251253
}
252254

@@ -366,53 +368,25 @@ impl Drop for ZArray {
366368
}
367369
}
368370

369-
/// Iterator key for [Iter].
371+
/// Iterator key for [`ZArr::for_each`].
370372
#[derive(Debug, Clone, PartialEq, From)]
371373
pub enum IterKey<'a> {
372374
Index(u64),
373375
ZStr(&'a ZStr),
374376
}
375377

376-
/// Iter created by [ZArr::iter].
377-
pub struct Iter<'a> {
378-
index: isize,
379-
array: &'a ZArr,
380-
}
381-
382-
impl<'a> Iterator for Iter<'a> {
383-
type Item = (IterKey<'a>, &'a ZVal);
384-
385-
fn next(&mut self) -> Option<Self::Item> {
386-
loop {
387-
if self.index >= self.array.inner.nNumUsed as isize {
388-
break None;
389-
}
390-
391-
unsafe {
392-
let bucket = self.array.inner.arData.offset(self.index);
393-
394-
let key = if (*bucket).key.is_null() {
395-
IterKey::Index((*bucket).h)
396-
} else {
397-
let s = ZStr::from_ptr((*bucket).key);
398-
IterKey::ZStr(s)
399-
};
400-
401-
let val = &mut (*bucket).val;
402-
let mut val = ZVal::from_mut_ptr(val);
403-
if val.get_type_info().is_indirect() {
404-
val = ZVal::from_mut_ptr((*val.as_mut_ptr()).value.zv);
405-
}
406-
407-
self.index += 1;
408-
409-
if val.get_type_info().is_undef() {
410-
continue;
411-
}
412-
break Some((key, val));
413-
}
414-
}
415-
}
378+
unsafe extern "C" fn for_each_callback(
379+
idx: zend_ulong, key: *mut zend_string, val: *mut zval, argument: *mut c_void,
380+
) {
381+
let f = (argument as *mut Box<dyn FnMut(IterKey<'_>, &'_ ZVal)>)
382+
.as_mut()
383+
.unwrap();
384+
let iter_key = if key.is_null() {
385+
IterKey::Index(idx as u64)
386+
} else {
387+
IterKey::ZStr(ZStr::from_ptr(key))
388+
};
389+
f(iter_key, ZVal::from_ptr(val));
416390
}
417391

418392
pub enum Entry<'a> {

phper/src/values.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ use phper_alloc::RefClone;
2525
use std::{
2626
convert::TryInto,
2727
ffi::CStr,
28+
fmt,
29+
fmt::Debug,
2830
marker::PhantomData,
2931
mem::{transmute, zeroed, ManuallyDrop, MaybeUninit},
3032
str,
@@ -132,7 +134,10 @@ impl ExecuteData {
132134
let num_args = self.num_args();
133135
let mut arguments = vec![zeroed::<zval>(); num_args as usize];
134136
if num_args > 0 {
135-
_zend_get_parameters_array_ex(num_args.try_into().unwrap(), arguments.as_mut_ptr());
137+
phper_zend_get_parameters_array_ex(
138+
num_args.try_into().unwrap(),
139+
arguments.as_mut_ptr(),
140+
);
136141
}
137142
transmute(arguments)
138143
}
@@ -378,6 +383,14 @@ impl ZVal {
378383
}
379384
}
380385

386+
impl Debug for ZVal {
387+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
388+
f.debug_struct("ZVal")
389+
.field("type", &self.get_type_info())
390+
.finish()
391+
}
392+
}
393+
381394
impl Default for ZVal {
382395
#[inline]
383396
fn default() -> Self {

tests/integration/src/arrays.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -187,15 +187,17 @@ pub fn integrate(module: &mut Module) {
187187
);
188188

189189
module.add_function(
190-
"integrate_arrays_iter",
190+
"integrate_arrays_for_each",
191191
|_: &mut [ZVal]| -> phper::Result<()> {
192192
let mut a = ZArray::new();
193193

194194
a.insert(0, ZVal::from(0));
195195
a.insert((), ZVal::from(1));
196196
a.insert("foo", ZVal::from("bar"));
197197

198-
for (i, (k, v)) in a.iter().enumerate() {
198+
let mut i = 0;
199+
200+
a.for_each(|k, v| {
199201
match i {
200202
0 => {
201203
assert_eq!(k, 0.into());
@@ -211,7 +213,11 @@ pub fn integrate(module: &mut Module) {
211213
}
212214
_ => unreachable!(),
213215
}
214-
}
216+
217+
i += 1;
218+
});
219+
220+
assert_eq!(i, 3);
215221

216222
Ok(())
217223
},

tests/integration/tests/php/arrays.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,4 @@
1717
integrate_arrays_types();
1818
integrate_arrays_insert();
1919
integrate_arrays_exists();
20-
integrate_arrays_iter();
20+
integrate_arrays_for_each();

0 commit comments

Comments
 (0)