Skip to content

Adapt to PHP 8.2. #86

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ jobs:
- "7.4"
- "8.0"
- "8.1"
- "8.2"

runs-on: ${{ matrix.os }}
steps:
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ The framework that allows us to write PHP extensions using pure and safe Rust wh
- [x] 7.4
- [x] 8.0
- [x] 8.1
- [x] 8.2
- **mode**
- [x] nts
- [ ] zts
Expand Down
12 changes: 9 additions & 3 deletions phper-doc/doc/_05_internal_types/_02_z_arr/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,24 @@ let _i = arr.get("10");
arr.remove("foo");
```

`ZArr` can be iterated by `iter()`.
`ZArr` can be iterated by `for_each()`.

```rust,no_run
use phper::arrays::ZArray;
use phper::values::ZVal;

let arr = ZArray::new();

for (_k, _v) in arr.iter() {
}

arr.for_each(|k, v| {
dbg!(k, v);
});
```

*I used to provide the `iter()` method for `ZArr`, and let `Iter` implement
`Iterator`, but if using the PHP stable macro `ZEND_HASH_FOREACH_KEY_VAL`, it is a
bit difficult to provide `iter`, so it is deleted.*;

`ZArr` implements `ToOwned`, can upgrade to `ZArray` by value copy via
`zend_array_dup`.

Expand Down
2 changes: 2 additions & 0 deletions phper-sys/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ fn main() {
let mut builder = Builder::default()
.header("php_wrapper.c")
.allowlist_file("php_wrapper\\.c")
// Block the `zend_ini_parse_quantity` because it's document causes the doc test to fail.
.blocklist_function("zend_ini_parse_quantity")
.clang_args(&includes)
.derive_default(true);

Expand Down
20 changes: 18 additions & 2 deletions phper-sys/php_wrapper.c
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,22 @@ uint32_t phper_zend_num_args(const zend_execute_data *execute_data) {
return ZEND_NUM_ARGS();
}

zend_bool phper_instanceof_function(const zend_class_entry *instance_ce, const zend_class_entry *ce) {
return instanceof_function(instance_ce, ce);
bool phper_instanceof_function(const zend_class_entry *instance_ce, const zend_class_entry *ce) {
return instanceof_function(instance_ce, ce) != 0;
}

bool phper_zend_get_parameters_array_ex(uint32_t param_count, zval *argument_array) {
return zend_get_parameters_array_ex(param_count, argument_array) != 0;
}

typedef void (*phper_foreach_func_arg_t)(zend_ulong idx, zend_string *key, zval *val, void *argument);

void phper_zend_hash_foreach_key_val(zend_array *array, phper_foreach_func_arg_t f, void *argument) {
zend_ulong idx;
zend_string *key;
zval *val;

ZEND_HASH_FOREACH_KEY_VAL(array, idx, key, val) {
f(idx, key, val, argument);
} ZEND_HASH_FOREACH_END();
}
66 changes: 20 additions & 46 deletions phper/src/arrays.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use derive_more::From;
use std::{
borrow::Borrow,
convert::TryInto,
ffi::c_void,
marker::PhantomData,
mem::{forget, ManuallyDrop},
ops::{Deref, DerefMut},
Expand Down Expand Up @@ -103,7 +104,7 @@ impl ZArr {
self.len() == 0
}

// Get items length.
/// Get items length.
#[inline]
pub fn len(&mut self) -> usize {
unsafe { zend_array_count(self.as_mut_ptr()).try_into().unwrap() }
Expand Down Expand Up @@ -243,10 +244,11 @@ impl ZArr {
}
}

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

Expand Down Expand Up @@ -366,53 +368,25 @@ impl Drop for ZArray {
}
}

/// Iterator key for [Iter].
/// Iterator key for [`ZArr::for_each`].
#[derive(Debug, Clone, PartialEq, From)]
pub enum IterKey<'a> {
Index(u64),
ZStr(&'a ZStr),
}

/// Iter created by [ZArr::iter].
pub struct Iter<'a> {
index: isize,
array: &'a ZArr,
}

impl<'a> Iterator for Iter<'a> {
type Item = (IterKey<'a>, &'a ZVal);

fn next(&mut self) -> Option<Self::Item> {
loop {
if self.index >= self.array.inner.nNumUsed as isize {
break None;
}

unsafe {
let bucket = self.array.inner.arData.offset(self.index);

let key = if (*bucket).key.is_null() {
IterKey::Index((*bucket).h)
} else {
let s = ZStr::from_ptr((*bucket).key);
IterKey::ZStr(s)
};

let val = &mut (*bucket).val;
let mut val = ZVal::from_mut_ptr(val);
if val.get_type_info().is_indirect() {
val = ZVal::from_mut_ptr((*val.as_mut_ptr()).value.zv);
}

self.index += 1;

if val.get_type_info().is_undef() {
continue;
}
break Some((key, val));
}
}
}
unsafe extern "C" fn for_each_callback(
idx: zend_ulong, key: *mut zend_string, val: *mut zval, argument: *mut c_void,
) {
let f = (argument as *mut Box<dyn FnMut(IterKey<'_>, &'_ ZVal)>)
.as_mut()
.unwrap();
let iter_key = if key.is_null() {
IterKey::Index(idx as u64)
} else {
IterKey::ZStr(ZStr::from_ptr(key))
};
f(iter_key, ZVal::from_ptr(val));
}

pub enum Entry<'a> {
Expand Down
15 changes: 14 additions & 1 deletion phper/src/values.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ use phper_alloc::RefClone;
use std::{
convert::TryInto,
ffi::CStr,
fmt,
fmt::Debug,
marker::PhantomData,
mem::{transmute, zeroed, ManuallyDrop, MaybeUninit},
str,
Expand Down Expand Up @@ -132,7 +134,10 @@ impl ExecuteData {
let num_args = self.num_args();
let mut arguments = vec![zeroed::<zval>(); num_args as usize];
if num_args > 0 {
_zend_get_parameters_array_ex(num_args.try_into().unwrap(), arguments.as_mut_ptr());
phper_zend_get_parameters_array_ex(
num_args.try_into().unwrap(),
arguments.as_mut_ptr(),
);
}
transmute(arguments)
}
Expand Down Expand Up @@ -378,6 +383,14 @@ impl ZVal {
}
}

impl Debug for ZVal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ZVal")
.field("type", &self.get_type_info())
.finish()
}
}

impl Default for ZVal {
#[inline]
fn default() -> Self {
Expand Down
12 changes: 9 additions & 3 deletions tests/integration/src/arrays.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,15 +187,17 @@ pub fn integrate(module: &mut Module) {
);

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

a.insert(0, ZVal::from(0));
a.insert((), ZVal::from(1));
a.insert("foo", ZVal::from("bar"));

for (i, (k, v)) in a.iter().enumerate() {
let mut i = 0;

a.for_each(|k, v| {
match i {
0 => {
assert_eq!(k, 0.into());
Expand All @@ -211,7 +213,11 @@ pub fn integrate(module: &mut Module) {
}
_ => unreachable!(),
}
}

i += 1;
});

assert_eq!(i, 3);

Ok(())
},
Expand Down
2 changes: 1 addition & 1 deletion tests/integration/tests/php/arrays.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@
integrate_arrays_types();
integrate_arrays_insert();
integrate_arrays_exists();
integrate_arrays_iter();
integrate_arrays_for_each();