From d36f7859d27fa8a088742a4db2c70b3ab887dabe Mon Sep 17 00:00:00 2001 From: jmjoy Date: Thu, 5 Jun 2025 21:11:40 +0800 Subject: [PATCH 1/6] Refactor owned object to EBox alias --- .gitignore | 1 + examples/complex/src/lib.rs | 5 +- examples/http-client/src/response.rs | 26 +++-- examples/http-server/src/request.rs | 5 +- phper-alloc/src/lib.rs | 80 +-------------- phper-alloc/src/macros.rs | 21 ---- phper/src/alloc.rs | 88 ++++++++++++++++ phper/src/arrays.rs | 92 ++++------------- phper/src/classes.rs | 8 +- phper/src/enums.rs | 9 +- phper/src/errors.rs | 28 +++--- phper/src/functions.rs | 4 +- phper/src/lib.rs | 2 +- phper/src/objects.rs | 134 ++++++------------------- phper/src/strings.rs | 97 ++++-------------- phper/src/values.rs | 13 +-- tests/integration/src/strings.rs | 6 +- tests/integration/src/values.rs | 9 -- tests/integration/tests/php/values.php | 1 - 19 files changed, 225 insertions(+), 404 deletions(-) delete mode 100644 phper-alloc/src/macros.rs create mode 100644 phper/src/alloc.rs diff --git a/.gitignore b/.gitignore index 77f6cf1e..b1458856 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ /.cargo /vendor core +compile_commands.json diff --git a/examples/complex/src/lib.rs b/examples/complex/src/lib.rs index 383a9b99..e7e92cff 100644 --- a/examples/complex/src/lib.rs +++ b/examples/complex/src/lib.rs @@ -9,7 +9,8 @@ // See the Mulan PSL v2 for more details. use phper::{ - arrays::ZArray, + alloc::EBox, + arrays::ZArr, classes::{ClassEntity, Visibility}, functions::Argument, ini::{Policy, ini_get}, @@ -61,7 +62,7 @@ pub fn get_module() -> Module { .argument(Argument::new("name")); module.add_function("complex_throw_exception", throw_exception); module.add_function("complex_get_all_ini", |_: &mut [ZVal]| { - let mut arr = ZArray::new(); + let mut arr = EBox::::new(); let complex_enable = ZVal::from(ini_get::("complex.enable")); arr.insert("complex.enable", complex_enable); diff --git a/examples/http-client/src/response.rs b/examples/http-client/src/response.rs index ff4378c2..32632220 100644 --- a/examples/http-client/src/response.rs +++ b/examples/http-client/src/response.rs @@ -10,7 +10,8 @@ use crate::errors::HttpClientError; use phper::{ - arrays::{InsertKey, ZArray}, + alloc::EBox, + arrays::{InsertKey, ZArr}, classes::{ClassEntity, StateClass, Visibility}, values::ZVal, }; @@ -50,16 +51,19 @@ pub fn make_response_class() -> ClassEntity> { .ok_or_else(|| HttpClientError::ResponseAfterRead { method_name: "headers".to_owned(), })?; - let headers_map = response - .headers() - .iter() - .fold(ZArray::new(), |mut acc, (key, value)| { - let arr = acc.entry(key.as_str()).or_insert(ZVal::from(ZArray::new())); - arr.as_mut_z_arr() - .unwrap() - .insert(InsertKey::NextIndex, ZVal::from(value.as_bytes())); - acc - }); + let headers_map = + response + .headers() + .iter() + .fold(EBox::::new(), |mut acc, (key, value)| { + let arr = acc + .entry(key.as_str()) + .or_insert(ZVal::from(EBox::::new())); + arr.as_mut_z_arr() + .unwrap() + .insert(InsertKey::NextIndex, ZVal::from(value.as_bytes())); + acc + }); Ok::<_, HttpClientError>(headers_map) }); diff --git a/examples/http-server/src/request.rs b/examples/http-server/src/request.rs index b0b74b0a..669c5cb7 100644 --- a/examples/http-server/src/request.rs +++ b/examples/http-server/src/request.rs @@ -9,7 +9,8 @@ // See the Mulan PSL v2 for more details. use phper::{ - arrays::ZArray, + alloc::EBox, + arrays::ZArr, classes::{ClassEntity, StateClass, Visibility}, }; use std::convert::Infallible; @@ -31,7 +32,7 @@ pub fn make_request_class() -> ClassEntity<()> { // Register the constructor method with public visibility, initialize the // headers with empty array. class.add_method("__construct", Visibility::Public, |this, _arguments| { - this.set_property("headers", ZArray::new()); + this.set_property("headers", EBox::::new()); Ok::<_, Infallible>(()) }); diff --git a/phper-alloc/src/lib.rs b/phper-alloc/src/lib.rs index 32b569fd..03381eba 100644 --- a/phper-alloc/src/lib.rs +++ b/phper-alloc/src/lib.rs @@ -12,85 +12,7 @@ #![warn(clippy::dbg_macro, clippy::print_stdout)] #![doc = include_str!("../README.md")] -#[macro_use] -mod macros; - -use phper_sys::*; -use std::{ - borrow::Borrow, - mem::{ManuallyDrop, size_of}, - ops::{Deref, DerefMut}, -}; - -/// The Box which use php `emalloc` and `efree` to manage memory. -/// -/// TODO Now feature `allocator_api` is still unstable, implement myself, use -/// Box later. -pub struct EBox { - ptr: *mut T, -} - -impl EBox { - /// Allocates heap memory using `emalloc` then places `x` into it. - /// - /// # Panic - /// - /// Panic if `size_of::()` equals zero. - #[allow(clippy::useless_conversion)] - pub fn new(x: T) -> Self { - unsafe { - assert_ne!(size_of::(), 0); - let ptr: *mut T = phper_emalloc(size_of::().try_into().unwrap()).cast(); - // TODO Deal with ptr is zero, when memory limit is reached. - ptr.write(x); - Self { ptr } - } - } - - /// Constructs from a raw pointer. - /// - /// # Safety - /// - /// Make sure the pointer is from `into_raw`, or created from `emalloc`. - pub unsafe fn from_raw(raw: *mut T) -> Self { - Self { ptr: raw } - } - - /// Consumes and returning a wrapped raw pointer. - /// - /// Will leak memory. - pub fn into_raw(b: EBox) -> *mut T { - ManuallyDrop::new(b).ptr - } - - /// Consumes the `EBox`, returning the wrapped value. - pub fn into_inner(self) -> T { - unsafe { self.ptr.read() } - } -} - -impl Deref for EBox { - type Target = T; - - fn deref(&self) -> &Self::Target { - unsafe { self.ptr.as_ref().unwrap() } - } -} - -impl DerefMut for EBox { - fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { self.ptr.as_mut().unwrap() } - } -} - -impl Drop for EBox { - fn drop(&mut self) { - unsafe { - self.ptr.drop_in_place(); - phper_efree(self.ptr.cast()); - } - } -} +use std::borrow::Borrow; /// Duplicate an object without deep copy, but to only add the refcount, for php /// refcount struct. diff --git a/phper-alloc/src/macros.rs b/phper-alloc/src/macros.rs deleted file mode 100644 index 399bfa77..00000000 --- a/phper-alloc/src/macros.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2022 PHPER Framework Team -// PHPER is licensed under Mulan PSL v2. -// You can use this software according to the terms and conditions of the Mulan -// PSL v2. You may obtain a copy of Mulan PSL v2 at: -// http://license.coscl.org.cn/MulanPSL2 -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY -// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. -// See the Mulan PSL v2 for more details. - -/// Wrapper of `EBox::new`. -/// -/// # Examples -/// -/// ```no_test -/// let _ = ebox!(1); -/// ``` -#[macro_export] -macro_rules! ebox { - ($arg:tt) => {{ $crate::EBox::new($arg) }}; -} diff --git a/phper/src/alloc.rs b/phper/src/alloc.rs new file mode 100644 index 00000000..abf1d6eb --- /dev/null +++ b/phper/src/alloc.rs @@ -0,0 +1,88 @@ +//! Memory allocation utilities and boxed types for PHP values. + +pub use phper_alloc::{RefClone, ToRefOwned}; +use std::{ + borrow::{Borrow, BorrowMut}, + fmt::{self}, + mem::ManuallyDrop, + ops::{Deref, DerefMut}, +}; + +/// A smart pointer for PHP values allocated in the Zend Engine memory. +/// +/// `EBox` provides owned access to values allocated in PHP's memory +/// management system. It automatically handles deallocation when dropped, +/// ensuring proper cleanup of PHP resources. +pub struct EBox { + ptr: *mut T, +} + +impl EBox { + /// Constructs from a raw pointer. + /// + /// # Safety + /// + /// Make sure the pointer is from `into_raw`, or created from `emalloc`. + pub unsafe fn from_raw(raw: *mut T) -> Self { + Self { ptr: raw } + } + + /// Consumes and returning a wrapped raw pointer. + /// + /// Will leak memory. + pub fn into_raw(b: EBox) -> *mut T { + ManuallyDrop::new(b).ptr + } +} + +impl fmt::Debug for EBox { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +impl Deref for EBox { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { self.ptr.as_ref().unwrap() } + } +} + +impl DerefMut for EBox { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { self.ptr.as_mut().unwrap() } + } +} + +impl Drop for EBox { + fn drop(&mut self) { + unsafe { + self.ptr.drop_in_place(); + } + } +} + +impl Borrow for EBox { + fn borrow(&self) -> &T { + unsafe { self.ptr.as_ref().unwrap() } + } +} + +impl BorrowMut for EBox { + fn borrow_mut(&mut self) -> &mut T { + unsafe { self.ptr.as_mut().unwrap() } + } +} + +impl AsRef for EBox { + fn as_ref(&self) -> &T { + unsafe { self.ptr.as_ref().unwrap() } + } +} + +impl AsMut for EBox { + fn as_mut(&mut self) -> &mut T { + unsafe { self.ptr.as_mut().unwrap() } + } +} diff --git a/phper/src/arrays.rs b/phper/src/arrays.rs index 0b855549..66aacb09 100644 --- a/phper/src/arrays.rs +++ b/phper/src/arrays.rs @@ -10,14 +10,14 @@ //! Apis relate to [zend_array]. -use crate::{alloc::ToRefOwned, strings::ZStr, sys::*, values::ZVal}; +use crate::{alloc::EBox, strings::ZStr, sys::*, values::ZVal}; use derive_more::From; +use phper_alloc::ToRefOwned; use std::{ - borrow::Borrow, fmt::{self, Debug}, marker::PhantomData, mem::ManuallyDrop, - ops::{Deref, DerefMut}, + ops::Deref, ptr::null_mut, }; @@ -333,12 +333,21 @@ impl ZArr { } } +impl Drop for ZArr { + fn drop(&mut self) { + unsafe { + zend_array_destroy(self.as_mut_ptr()); + } + } +} + impl Debug for ZArr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { common_fmt(self, f, "ZArr") } } +#[allow(deprecated)] impl ToOwned for ZArr { type Owned = ZArray; @@ -346,7 +355,7 @@ impl ToOwned for ZArr { unsafe { // TODO The source really immutable? let dest = phper_zend_array_dup(self.as_ptr() as *mut _); - ZArray::from_raw(dest) + ZArray::from_raw(dest.cast()) } } } @@ -359,16 +368,17 @@ impl ToRefOwned for ZArr { unsafe { phper_zval_arr(val.as_mut_ptr(), self.as_mut_ptr()); phper_z_addref_p(val.as_mut_ptr()); - ZArray::from_raw(val.as_mut_z_arr().unwrap().as_mut_ptr()) + ZArray::from_raw(val.as_mut_z_arr().unwrap().as_mut_ptr().cast()) } } } -/// Wrapper of [zend_array]. -#[repr(transparent)] -pub struct ZArray { - inner: *mut ZArr, -} +/// An owned PHP array value. +/// +/// `ZArray` represents an owned PHP array (hashtable) allocated in the Zend +/// Engine memory. It provides safe access to PHP array operations and +/// automatically manages memory cleanup. +pub type ZArray = EBox; impl ZArray { /// Creates an empty `ZArray`. @@ -384,82 +394,24 @@ impl ZArray { pub fn with_capacity(n: usize) -> Self { unsafe { let ptr = phper_zend_new_array(n.try_into().unwrap()); - Self::from_raw(ptr) + Self::from_raw(ptr.cast()) } } - - /// Create owned object From raw pointer, usually used in pairs with - /// `into_raw`. - /// - /// # Safety - /// - /// This function is unsafe because improper use may lead to memory - /// problems. For example, a double-free may occur if the function is called - /// twice on the same raw pointer. - #[inline] - pub unsafe fn from_raw(ptr: *mut zend_array) -> Self { - unsafe { - Self { - inner: ZArr::from_mut_ptr(ptr), - } - } - } - - /// Consumes the `ZArray` and transfers ownership to a raw pointer. - /// - /// Failure to call [`ZArray::from_raw`] will lead to a memory leak. - #[inline] - pub fn into_raw(self) -> *mut zend_array { - ManuallyDrop::new(self).as_mut_ptr() - } -} - -impl Debug for ZArray { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - common_fmt(self, f, "ZArray") - } } +#[allow(deprecated)] impl Default for ZArray { fn default() -> Self { Self::new() } } -impl Deref for ZArray { - type Target = ZArr; - - fn deref(&self) -> &Self::Target { - unsafe { self.inner.as_ref().unwrap() } - } -} - -impl DerefMut for ZArray { - fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { self.inner.as_mut().unwrap() } - } -} - -impl Borrow for ZArray { - fn borrow(&self) -> &ZArr { - self.deref() - } -} - impl Clone for ZArray { fn clone(&self) -> Self { self.deref().to_owned() } } -impl Drop for ZArray { - fn drop(&mut self) { - unsafe { - zend_array_destroy(self.as_mut_ptr()); - } - } -} - /// Iterator key for [`ZArr::iter`] and [`ZArr::iter_mut`]. #[derive(Debug, Clone, PartialEq, From)] pub enum IterKey<'a> { diff --git a/phper/src/classes.rs b/phper/src/classes.rs index 4dbb769e..9acdf24e 100644 --- a/phper/src/classes.rs +++ b/phper/src/classes.rs @@ -127,6 +127,7 @@ impl ClassEntry { /// /// If the `__construct` is private, or protected and the called scope isn't /// parent class, it will throw PHP Error. + #[allow(deprecated)] pub fn new_object(&self, arguments: impl AsMut<[ZVal]>) -> crate::Result { let mut object = self.init_object()?; object.call_construct(arguments)?; @@ -136,6 +137,7 @@ impl ClassEntry { /// Create the object from class, without calling `__construct`. /// /// **Be careful when `__construct` is necessary.** + #[allow(deprecated)] pub fn init_object(&self) -> crate::Result { unsafe { let ptr = self.as_ptr() as *mut _; @@ -147,7 +149,7 @@ impl ClassEntry { // day of debugging time here). let mut val = ManuallyDrop::new(val); let ptr = phper_z_obj_p(val.as_mut_ptr()); - Ok(ZObject::from_raw(ptr)) + Ok(ZObject::from_raw(ptr.cast())) } } } @@ -331,20 +333,24 @@ impl StateClass { /// /// If the `__construct` is private, or protected and the called scope isn't /// parent class, it will throw PHP Error. + #[allow(deprecated)] pub fn new_object(&self, arguments: impl AsMut<[ZVal]>) -> crate::Result> { self.as_class_entry() .new_object(arguments) .map(ZObject::into_raw) + .map(|ptr| ptr.cast()) .map(StateObject::::from_raw_object) } /// Create the object from class, without calling `__construct`. /// /// **Be careful when `__construct` is necessary.** + #[allow(deprecated)] pub fn init_object(&self) -> crate::Result> { self.as_class_entry() .init_object() .map(ZObject::into_raw) + .map(|ptr| ptr.cast()) .map(StateObject::::from_raw_object) } } diff --git a/phper/src/enums.rs b/phper/src/enums.rs index f007ccf7..ca6e98e3 100644 --- a/phper/src/enums.rs +++ b/phper/src/enums.rs @@ -20,13 +20,14 @@ #![cfg(phper_enum_supported)] use crate::{ + alloc::EBox, classes::{ ClassEntry, ConstantEntity, InnerClassEntry, Interface, Visibility, add_class_constant, }, errors::Throwable, functions::{Function, FunctionEntry, HandlerMap, MethodEntity}, objects::ZObj, - strings::ZString, + strings::ZStr, sys::*, types::Scalar, utils::ensure_end_with_zero, @@ -260,7 +261,7 @@ impl Enum { unsafe { let ce = self.as_class_entry().as_ptr() as *mut _; let case_name_str = case_name.as_ref(); - let mut name_zstr = ZString::new(case_name_str); + let mut name_zstr = EBox::::new(case_name_str); // Get the enum case let case_obj = zend_enum_get_case(ce, name_zstr.as_mut_ptr()); @@ -296,7 +297,7 @@ impl Enum { unsafe { let ce = self.as_class_entry().as_ptr() as *mut _; let case_name_str = case_name.as_ref(); - let mut name_zstr = ZString::new(case_name_str); + let mut name_zstr = EBox::::new(case_name_str); // Get the enum case let case_obj = zend_enum_get_case(ce, name_zstr.as_mut_ptr()); @@ -528,7 +529,7 @@ unsafe fn register_enum_case( ); } Scalar::String(value) => { - let value = ZString::new_persistent(value); + let value = EBox::::new_persistent(value); let mut value = ManuallyDrop::new(ZVal::from(value)); zend_enum_add_case_cstr(class_ce, case_name.as_ptr(), value.as_mut_ptr()); } diff --git a/phper/src/errors.rs b/phper/src/errors.rs index 13435b2d..309e8f51 100644 --- a/phper/src/errors.rs +++ b/phper/src/errors.rs @@ -10,7 +10,9 @@ //! The errors for crate and php. -use crate::{classes::ClassEntry, objects::ZObject, sys::*, types::TypeInfo, values::ZVal}; +use crate::{ + alloc::EBox, classes::ClassEntry, objects::ZObj, sys::*, types::TypeInfo, values::ZVal, +}; use derive_more::Constructor; use phper_alloc::ToRefOwned; use std::{ @@ -105,9 +107,9 @@ pub trait Throwable: error::Error { /// /// By default, the Exception is instance of `get_class()`, the code is /// `get_code` and message is `get_message`; - fn to_object(&mut self) -> result::Result> { - let mut object = - ZObject::new(self.get_class(), []).map_err(|e| Box::new(e) as Box)?; + fn to_object(&mut self) -> result::Result, Box> { + let mut object = EBox::::new(self.get_class(), []) + .map_err(|e| Box::new(e) as Box)?; if let Some(code) = self.get_code() { object.set_property("code", code); } @@ -131,7 +133,8 @@ impl Throwable for Box { Throwable::get_message(self.deref()) } - fn to_object(&mut self) -> result::Result> { + #[allow(deprecated)] + fn to_object(&mut self) -> result::Result, Box> { Throwable::to_object(self.deref_mut()) } } @@ -155,7 +158,8 @@ impl Throwable for Infallible { match *self {} } - fn to_object(&mut self) -> result::Result> { + #[allow(deprecated)] + fn to_object(&mut self) -> result::Result, Box> { match *self {} } } @@ -274,7 +278,7 @@ impl Throwable for Error { } } - fn to_object(&mut self) -> result::Result> { + fn to_object(&mut self) -> result::Result, Box> { match self { Error::Io(e) => Throwable::to_object(e as &mut dyn error::Error), Error::Utf8(e) => Throwable::to_object(e as &mut dyn error::Error), @@ -292,13 +296,13 @@ impl Throwable for Error { /// Wrapper of Throwable object. #[derive(Debug)] -pub struct ThrowObject(ZObject); +pub struct ThrowObject(EBox); impl ThrowObject { /// Construct from Throwable object. /// /// Failed if the object is not instance of php `Throwable`. - pub fn new(obj: ZObject) -> result::Result { + pub fn new(obj: EBox) -> result::Result { if !obj.get_class().is_instance_of(throwable_class()) { return Err(NotImplementThrowableError); } @@ -318,7 +322,7 @@ impl ThrowObject { Self::from_result(Throwable::to_object(e)) } - fn from_result(mut result: result::Result>) -> Self { + fn from_result(mut result: result::Result, Box>) -> Self { let mut i = 0; let obj = loop { @@ -339,7 +343,7 @@ impl ThrowObject { /// Consumes the `ThrowObject`, returning the wrapped object. #[inline] - pub fn into_inner(self) -> ZObject { + pub fn into_inner(self) -> EBox { self.0 } @@ -386,7 +390,7 @@ impl Throwable for ThrowObject { } #[inline] - fn to_object(&mut self) -> result::Result> { + fn to_object(&mut self) -> result::Result, Box> { Ok(self.0.to_ref_owned()) } } diff --git a/phper/src/functions.rs b/phper/src/functions.rs index 44e8d671..0ab11199 100644 --- a/phper/src/functions.rs +++ b/phper/src/functions.rs @@ -651,7 +651,7 @@ impl ZFunc { pub fn get_function_or_method_name(&self) -> ZString { unsafe { let s = phper_get_function_or_method_name(self.as_ptr()); - ZString::from_raw(s) + ZString::from_raw(s.cast()) } } @@ -890,7 +890,7 @@ pub(crate) fn call_raw_common(call_fn: impl FnOnce(&mut ZVal)) -> crate::Result< if !eg!(exception).is_null() { #[allow(static_mut_refs)] let e = ptr::replace(&mut eg!(exception), null_mut()); - let obj = ZObject::from_raw(e); + let obj = ZObject::from_raw(e.cast()); match ThrowObject::new(obj) { Ok(e) => return Err(e.into()), Err(e) => return Err(e.into()), diff --git a/phper/src/lib.rs b/phper/src/lib.rs index 1a2800c5..7a7a6f97 100644 --- a/phper/src/lib.rs +++ b/phper/src/lib.rs @@ -16,6 +16,7 @@ #[macro_use] mod macros; +pub mod alloc; pub mod arrays; pub mod classes; pub(crate) mod constants; @@ -34,6 +35,5 @@ mod utils; pub mod values; pub use crate::errors::{Error, Result, ok}; -pub use phper_alloc as alloc; pub use phper_macros::*; pub use phper_sys as sys; diff --git a/phper/src/objects.rs b/phper/src/objects.rs index 5969772c..2a9bd591 100644 --- a/phper/src/objects.rs +++ b/phper/src/objects.rs @@ -11,6 +11,7 @@ //! Apis relate to [zend_object]. use crate::{ + alloc::EBox, classes::ClassEntry, functions::{ZFunc, call_internal, call_raw_common}, sys::*, @@ -19,7 +20,6 @@ use crate::{ use phper_alloc::{RefClone, ToRefOwned}; use std::{ any::Any, - borrow::Borrow, ffi::c_void, fmt::{self, Debug}, marker::PhantomData, @@ -266,6 +266,14 @@ impl ZObj { } } +impl Drop for ZObj { + fn drop(&mut self) { + unsafe { + phper_zend_object_release(self.as_mut_ptr()); + } + } +} + impl ToRefOwned for ZObj { type Owned = ZObject; @@ -274,7 +282,7 @@ impl ToRefOwned for ZObj { unsafe { phper_zval_obj(val.as_mut_ptr(), self.as_mut_ptr()); phper_z_addref_p(val.as_mut_ptr()); - ZObject::from_raw(val.as_mut_z_obj().unwrap().as_mut_ptr()) + ZObject::from_raw(val.as_mut_z_obj().unwrap().as_mut_ptr().cast()) } } } @@ -285,10 +293,12 @@ impl Debug for ZObj { } } -/// Wrapper of [zend_object]. -pub struct ZObject { - inner: *mut ZObj, -} +/// An owned PHP object value. +/// +/// `ZObject` represents an owned PHP object allocated in the Zend Engine +/// memory. It provides safe access to PHP object operations and automatically +/// manages memory cleanup. +pub type ZObject = EBox; impl ZObject { /// Another way to new object like [crate::classes::ClassEntry::new_object]. @@ -308,29 +318,6 @@ impl ZObject { pub fn new_by_std_class() -> Self { Self::new_by_class_name("stdclass", &mut []).unwrap() } - - /// Create owned object From raw pointer, usually used in pairs with - /// `into_raw`. - /// - /// # Safety - /// - /// This function is unsafe because improper use may lead to memory - /// problems. For example, a double-free may occur if the function is called - /// twice on the same raw pointer. - #[inline] - pub unsafe fn from_raw(ptr: *mut zend_object) -> Self { - unsafe { - Self { - inner: ZObj::from_mut_ptr(ptr), - } - } - } - - /// Consumes and returning a wrapped raw pointer. - #[inline] - pub fn into_raw(self) -> *mut zend_object { - ManuallyDrop::new(self).as_mut_ptr() - } } impl RefClone for ZObject { @@ -340,40 +327,6 @@ impl RefClone for ZObject { } } -impl Deref for ZObject { - type Target = ZObj; - - fn deref(&self) -> &Self::Target { - unsafe { self.inner.as_ref().unwrap() } - } -} - -impl DerefMut for ZObject { - fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { self.inner.as_mut().unwrap() } - } -} - -impl Borrow for ZObject { - fn borrow(&self) -> &ZObj { - self.deref() - } -} - -impl Drop for ZObject { - fn drop(&mut self) { - unsafe { - phper_zend_object_release(self.as_mut_ptr()); - } - } -} - -impl Debug for ZObject { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - common_fmt(self, f, "ZObject") - } -} - pub(crate) type AnyState = *mut dyn Any; /// The object owned state, usually as the parameter of method handler. @@ -454,6 +407,14 @@ impl StateObj { } } +impl Drop for StateObj { + fn drop(&mut self) { + unsafe { + phper_zend_object_release(self.as_mut_ptr()); + } + } +} + impl Deref for StateObj { type Target = ZObj; @@ -474,20 +435,17 @@ impl Debug for StateObj { } } -/// The object owned state, usually crated by -/// [StateClass](crate::classes::StateClass). -pub struct StateObject { - inner: *mut StateObj, -} +/// An owned PHP object with associated Rust state. +/// +/// `StateObject` represents an owned PHP object that contains additional +/// Rust state of type `T`. This allows embedding custom Rust data structures +/// within PHP objects while maintaining proper memory management and cleanup. +pub type StateObject = EBox>; impl StateObject { #[inline] pub(crate) fn from_raw_object(object: *mut zend_object) -> Self { - unsafe { - Self { - inner: StateObj::from_mut_object_ptr(object), - } - } + unsafe { Self::from_raw(StateObj::from_mut_object_ptr(object)) } } #[inline] @@ -497,7 +455,7 @@ impl StateObject { /// Converts into [ZObject]. pub fn into_z_object(self) -> ZObject { - unsafe { ZObject::from_raw(self.into_raw_object()) } + unsafe { ZObject::from_raw(self.into_raw_object().cast()) } } } @@ -520,34 +478,6 @@ impl StateObject { } } -impl Drop for StateObject { - fn drop(&mut self) { - unsafe { - drop(ZObject::from_raw(self.as_mut_ptr())); - } - } -} - -impl Deref for StateObject { - type Target = StateObj; - - fn deref(&self) -> &Self::Target { - unsafe { self.inner.as_ref().unwrap() } - } -} - -impl DerefMut for StateObject { - fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { self.inner.as_mut().unwrap() } - } -} - -impl Debug for StateObject { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - common_fmt(self, f, "StateObject") - } -} - fn common_fmt(this: &ZObj, f: &mut fmt::Formatter<'_>, name: &str) -> fmt::Result { let mut d = f.debug_struct(name); match this.get_class().get_name().to_c_str() { diff --git a/phper/src/strings.rs b/phper/src/strings.rs index 2a35046a..1b16abef 100644 --- a/phper/src/strings.rs +++ b/phper/src/strings.rs @@ -10,15 +10,13 @@ //! Apis relate to [zend_string]. -use crate::sys::*; +use crate::{alloc::EBox, sys::*}; use phper_alloc::ToRefOwned; use std::{ - borrow::{Borrow, Cow}, + borrow::Cow, ffi::{CStr, FromBytesWithNulError}, fmt::{self, Debug}, marker::PhantomData, - mem::forget, - ops::{Deref, DerefMut}, os::raw::c_char, slice::from_raw_parts, str::{self, Utf8Error}, @@ -137,6 +135,14 @@ impl ZStr { } } +impl Drop for ZStr { + fn drop(&mut self) { + unsafe { + phper_zend_string_release(self.as_mut_ptr()); + } + } +} + impl Debug for ZStr { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { common_fmt(self, f, "ZStr") @@ -169,15 +175,17 @@ impl ToRefOwned for ZStr { fn to_ref_owned(&mut self) -> Self::Owned { unsafe { let ptr = phper_zend_string_copy(self.as_mut_ptr()); - ZString::from_raw(ptr) + ZString::from_raw(ptr.cast()) } } } -/// Like String, CString for [zend_string]. -pub struct ZString { - inner: *mut ZStr, -} +/// An owned PHP string value. +/// +/// `ZString` represents an owned PHP string (zend_string) allocated in the Zend +/// Engine memory. It provides safe access to PHP string operations and +/// automatically manages memory cleanup using reference counting. +pub type ZString = EBox; impl ZString { /// Creates a new zend string from a container of bytes. @@ -190,7 +198,7 @@ impl ZString { s.len().try_into().unwrap(), false.into(), ); - Self::from_raw(ptr) + Self::from_raw(ptr.cast()) } } @@ -201,41 +209,9 @@ impl ZString { let s = s.as_ref(); let ptr = phper_zend_string_init(s.as_ptr().cast(), s.len().try_into().unwrap(), true.into()); - Self::from_raw(ptr) + Self::from_raw(ptr.cast()) } } - - /// Create owned object From raw pointer, usually used in pairs with - /// `into_raw`. - /// - /// # Safety - /// - /// This function is unsafe because improper use may lead to memory - /// problems. For example, a double-free may occur if the function is called - /// twice on the same raw pointer. - #[inline] - pub unsafe fn from_raw(ptr: *mut zend_string) -> Self { - unsafe { - Self { - inner: ZStr::from_mut_ptr(ptr), - } - } - } - - /// Consumes the ZString and transfers ownership of the string to a raw - /// pointer. - #[inline] - pub fn into_raw(mut self) -> *mut zend_string { - let ptr = self.as_mut_ptr(); - forget(self); - ptr - } -} - -impl Debug for ZString { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - common_fmt(self, f, "ZString") - } } impl Clone for ZString { @@ -246,33 +222,11 @@ impl Clone for ZString { phper_zstr_len(self.as_ptr()).try_into().unwrap(), false.into(), ); - Self { - inner: ZStr::from_mut_ptr(ptr.cast()), - } + Self::from_raw(ZStr::from_mut_ptr(ptr.cast())) } } } -impl Deref for ZString { - type Target = ZStr; - - fn deref(&self) -> &Self::Target { - unsafe { self.inner.as_ref().unwrap() } - } -} - -impl DerefMut for ZString { - fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { self.inner.as_mut().unwrap() } - } -} - -impl Borrow for ZString { - fn borrow(&self) -> &ZStr { - self.deref() - } -} - impl AsRef<[u8]> for ZString { fn as_ref(&self) -> &[u8] { self.to_bytes() @@ -281,15 +235,8 @@ impl AsRef<[u8]> for ZString { impl> PartialEq for ZString { fn eq(&self, other: &Rhs) -> bool { - self.as_ref() == other.as_ref() - } -} - -impl Drop for ZString { - fn drop(&mut self) { - unsafe { - phper_zend_string_release(self.as_mut_ptr()); - } + let this: &[u8] = self.as_ref(); + this == other.as_ref() } } diff --git a/phper/src/values.rs b/phper/src/values.rs index f45a14f0..d41f19ab 100644 --- a/phper/src/values.rs +++ b/phper/src/values.rs @@ -11,7 +11,6 @@ //! Apis relate to [zval]. use crate::{ - alloc::EBox, arrays::{ZArr, ZArray}, errors::ExpectTypeError, functions::{ZFunc, call_internal}, @@ -737,7 +736,7 @@ impl From for ZVal { fn from(s: ZString) -> Self { unsafe { let mut val = MaybeUninit::::uninit(); - phper_zval_str(val.as_mut_ptr().cast(), s.into_raw()); + phper_zval_str(val.as_mut_ptr().cast(), ZString::into_raw(s).cast()); val.assume_init() } } @@ -747,7 +746,7 @@ impl From for ZVal { fn from(arr: ZArray) -> Self { unsafe { let mut val = MaybeUninit::::uninit(); - phper_zval_arr(val.as_mut_ptr().cast(), arr.into_raw()); + phper_zval_arr(val.as_mut_ptr().cast(), ZArray::into_raw(arr).cast()); val.assume_init() } } @@ -757,7 +756,7 @@ impl From for ZVal { fn from(obj: ZObject) -> Self { unsafe { let mut val = MaybeUninit::::uninit(); - phper_zval_obj(val.as_mut_ptr().cast(), obj.into_raw()); + phper_zval_obj(val.as_mut_ptr().cast(), ZObject::into_raw(obj).cast()); val.assume_init() } } @@ -777,9 +776,3 @@ impl> From> for ZVal { } } } - -impl> From> for ZVal { - fn from(t: EBox) -> Self { - t.into_inner().into() - } -} diff --git a/tests/integration/src/strings.rs b/tests/integration/src/strings.rs index 2e9875e7..b95fd926 100644 --- a/tests/integration/src/strings.rs +++ b/tests/integration/src/strings.rs @@ -18,7 +18,8 @@ pub fn integrate(module: &mut Module) { assert_eq!(zs.to_str()?, "hello"); let zs = ZString::new([1, 2, 3]); - assert_eq!(zs.as_ref(), &[1, 2, 3]); + let zs: &[u8] = zs.as_ref(); + assert_eq!(zs, &[1, 2, 3]); assert!(ZString::new("hello") == ZString::new(b"hello")); @@ -33,7 +34,8 @@ pub fn integrate(module: &mut Module) { assert_eq!(zs.to_str()?, "persistent_hello"); let zs = ZString::new_persistent([4, 5, 6]); - assert_eq!(zs.as_ref(), &[4, 5, 6]); + let zs: &[u8] = zs.as_ref(); + assert_eq!(zs, &[4, 5, 6]); assert!( ZString::new_persistent("persistent") == ZString::new_persistent(b"persistent") diff --git a/tests/integration/src/values.rs b/tests/integration/src/values.rs index c8a206e3..2f35f38e 100644 --- a/tests/integration/src/values.rs +++ b/tests/integration/src/values.rs @@ -9,7 +9,6 @@ // See the Mulan PSL v2 for more details. use phper::{ - alloc::{EBox, ebox}, arrays::{InsertKey, ZArray}, modules::Module, objects::ZObject, @@ -71,10 +70,6 @@ fn integrate_returns(module: &mut Module) { "integration_values_return_option_i64_none", integration_values_return_option_i64_none, ); - module.add_function( - "integration_values_return_ebox_i64", - integration_values_return_ebox_i64, - ); module.add_function( "integration_values_return_result_string_ok", integration_values_return_result_string_ok, @@ -146,10 +141,6 @@ fn integration_values_return_option_i64_none(_: &mut [ZVal]) -> Result Result, Infallible> { - Ok(ebox!(64)) -} - fn integration_values_return_result_string_ok( _: &mut [ZVal], ) -> phper::Result + use<>> { diff --git a/tests/integration/tests/php/values.php b/tests/integration/tests/php/values.php index 991c7721..2588b76c 100644 --- a/tests/integration/tests/php/values.php +++ b/tests/integration/tests/php/values.php @@ -25,7 +25,6 @@ assert_object(integration_values_return_object(), "stdClass", ["foo" => "bar"]); assert_eq(integration_values_return_option_i64_some(), 64); assert_eq(integration_values_return_option_i64_none(), null); -assert_eq(integration_values_return_ebox_i64(), 64); assert_eq(integration_values_return_result_string_ok(), "foo"); assert_throw("integration_values_return_result_string_err", "ErrorException", 0, "a zhe"); assert_eq(integration_values_return_val(), "foo"); From 5230fb1d00105cbb8ac6b20896d72da068781b1c Mon Sep 17 00:00:00 2001 From: jmjoy Date: Thu, 5 Jun 2025 21:27:57 +0800 Subject: [PATCH 2/6] refactor: replace EBox with ZArray and ZString in multiple files --- examples/complex/src/lib.rs | 5 ++--- examples/http-client/src/response.rs | 26 +++++++++++--------------- examples/http-server/src/request.rs | 5 ++--- phper/src/arrays.rs | 2 -- phper/src/classes.rs | 4 ---- phper/src/enums.rs | 9 ++++----- phper/src/errors.rs | 28 ++++++++++++---------------- 7 files changed, 31 insertions(+), 48 deletions(-) diff --git a/examples/complex/src/lib.rs b/examples/complex/src/lib.rs index e7e92cff..383a9b99 100644 --- a/examples/complex/src/lib.rs +++ b/examples/complex/src/lib.rs @@ -9,8 +9,7 @@ // See the Mulan PSL v2 for more details. use phper::{ - alloc::EBox, - arrays::ZArr, + arrays::ZArray, classes::{ClassEntity, Visibility}, functions::Argument, ini::{Policy, ini_get}, @@ -62,7 +61,7 @@ pub fn get_module() -> Module { .argument(Argument::new("name")); module.add_function("complex_throw_exception", throw_exception); module.add_function("complex_get_all_ini", |_: &mut [ZVal]| { - let mut arr = EBox::::new(); + let mut arr = ZArray::new(); let complex_enable = ZVal::from(ini_get::("complex.enable")); arr.insert("complex.enable", complex_enable); diff --git a/examples/http-client/src/response.rs b/examples/http-client/src/response.rs index 32632220..ff4378c2 100644 --- a/examples/http-client/src/response.rs +++ b/examples/http-client/src/response.rs @@ -10,8 +10,7 @@ use crate::errors::HttpClientError; use phper::{ - alloc::EBox, - arrays::{InsertKey, ZArr}, + arrays::{InsertKey, ZArray}, classes::{ClassEntity, StateClass, Visibility}, values::ZVal, }; @@ -51,19 +50,16 @@ pub fn make_response_class() -> ClassEntity> { .ok_or_else(|| HttpClientError::ResponseAfterRead { method_name: "headers".to_owned(), })?; - let headers_map = - response - .headers() - .iter() - .fold(EBox::::new(), |mut acc, (key, value)| { - let arr = acc - .entry(key.as_str()) - .or_insert(ZVal::from(EBox::::new())); - arr.as_mut_z_arr() - .unwrap() - .insert(InsertKey::NextIndex, ZVal::from(value.as_bytes())); - acc - }); + let headers_map = response + .headers() + .iter() + .fold(ZArray::new(), |mut acc, (key, value)| { + let arr = acc.entry(key.as_str()).or_insert(ZVal::from(ZArray::new())); + arr.as_mut_z_arr() + .unwrap() + .insert(InsertKey::NextIndex, ZVal::from(value.as_bytes())); + acc + }); Ok::<_, HttpClientError>(headers_map) }); diff --git a/examples/http-server/src/request.rs b/examples/http-server/src/request.rs index 669c5cb7..b0b74b0a 100644 --- a/examples/http-server/src/request.rs +++ b/examples/http-server/src/request.rs @@ -9,8 +9,7 @@ // See the Mulan PSL v2 for more details. use phper::{ - alloc::EBox, - arrays::ZArr, + arrays::ZArray, classes::{ClassEntity, StateClass, Visibility}, }; use std::convert::Infallible; @@ -32,7 +31,7 @@ pub fn make_request_class() -> ClassEntity<()> { // Register the constructor method with public visibility, initialize the // headers with empty array. class.add_method("__construct", Visibility::Public, |this, _arguments| { - this.set_property("headers", EBox::::new()); + this.set_property("headers", ZArray::new()); Ok::<_, Infallible>(()) }); diff --git a/phper/src/arrays.rs b/phper/src/arrays.rs index 66aacb09..437d3bd7 100644 --- a/phper/src/arrays.rs +++ b/phper/src/arrays.rs @@ -347,7 +347,6 @@ impl Debug for ZArr { } } -#[allow(deprecated)] impl ToOwned for ZArr { type Owned = ZArray; @@ -399,7 +398,6 @@ impl ZArray { } } -#[allow(deprecated)] impl Default for ZArray { fn default() -> Self { Self::new() diff --git a/phper/src/classes.rs b/phper/src/classes.rs index 9acdf24e..694c8a6d 100644 --- a/phper/src/classes.rs +++ b/phper/src/classes.rs @@ -127,7 +127,6 @@ impl ClassEntry { /// /// If the `__construct` is private, or protected and the called scope isn't /// parent class, it will throw PHP Error. - #[allow(deprecated)] pub fn new_object(&self, arguments: impl AsMut<[ZVal]>) -> crate::Result { let mut object = self.init_object()?; object.call_construct(arguments)?; @@ -137,7 +136,6 @@ impl ClassEntry { /// Create the object from class, without calling `__construct`. /// /// **Be careful when `__construct` is necessary.** - #[allow(deprecated)] pub fn init_object(&self) -> crate::Result { unsafe { let ptr = self.as_ptr() as *mut _; @@ -333,7 +331,6 @@ impl StateClass { /// /// If the `__construct` is private, or protected and the called scope isn't /// parent class, it will throw PHP Error. - #[allow(deprecated)] pub fn new_object(&self, arguments: impl AsMut<[ZVal]>) -> crate::Result> { self.as_class_entry() .new_object(arguments) @@ -345,7 +342,6 @@ impl StateClass { /// Create the object from class, without calling `__construct`. /// /// **Be careful when `__construct` is necessary.** - #[allow(deprecated)] pub fn init_object(&self) -> crate::Result> { self.as_class_entry() .init_object() diff --git a/phper/src/enums.rs b/phper/src/enums.rs index ca6e98e3..f007ccf7 100644 --- a/phper/src/enums.rs +++ b/phper/src/enums.rs @@ -20,14 +20,13 @@ #![cfg(phper_enum_supported)] use crate::{ - alloc::EBox, classes::{ ClassEntry, ConstantEntity, InnerClassEntry, Interface, Visibility, add_class_constant, }, errors::Throwable, functions::{Function, FunctionEntry, HandlerMap, MethodEntity}, objects::ZObj, - strings::ZStr, + strings::ZString, sys::*, types::Scalar, utils::ensure_end_with_zero, @@ -261,7 +260,7 @@ impl Enum { unsafe { let ce = self.as_class_entry().as_ptr() as *mut _; let case_name_str = case_name.as_ref(); - let mut name_zstr = EBox::::new(case_name_str); + let mut name_zstr = ZString::new(case_name_str); // Get the enum case let case_obj = zend_enum_get_case(ce, name_zstr.as_mut_ptr()); @@ -297,7 +296,7 @@ impl Enum { unsafe { let ce = self.as_class_entry().as_ptr() as *mut _; let case_name_str = case_name.as_ref(); - let mut name_zstr = EBox::::new(case_name_str); + let mut name_zstr = ZString::new(case_name_str); // Get the enum case let case_obj = zend_enum_get_case(ce, name_zstr.as_mut_ptr()); @@ -529,7 +528,7 @@ unsafe fn register_enum_case( ); } Scalar::String(value) => { - let value = EBox::::new_persistent(value); + let value = ZString::new_persistent(value); let mut value = ManuallyDrop::new(ZVal::from(value)); zend_enum_add_case_cstr(class_ce, case_name.as_ptr(), value.as_mut_ptr()); } diff --git a/phper/src/errors.rs b/phper/src/errors.rs index 309e8f51..13435b2d 100644 --- a/phper/src/errors.rs +++ b/phper/src/errors.rs @@ -10,9 +10,7 @@ //! The errors for crate and php. -use crate::{ - alloc::EBox, classes::ClassEntry, objects::ZObj, sys::*, types::TypeInfo, values::ZVal, -}; +use crate::{classes::ClassEntry, objects::ZObject, sys::*, types::TypeInfo, values::ZVal}; use derive_more::Constructor; use phper_alloc::ToRefOwned; use std::{ @@ -107,9 +105,9 @@ pub trait Throwable: error::Error { /// /// By default, the Exception is instance of `get_class()`, the code is /// `get_code` and message is `get_message`; - fn to_object(&mut self) -> result::Result, Box> { - let mut object = EBox::::new(self.get_class(), []) - .map_err(|e| Box::new(e) as Box)?; + fn to_object(&mut self) -> result::Result> { + let mut object = + ZObject::new(self.get_class(), []).map_err(|e| Box::new(e) as Box)?; if let Some(code) = self.get_code() { object.set_property("code", code); } @@ -133,8 +131,7 @@ impl Throwable for Box { Throwable::get_message(self.deref()) } - #[allow(deprecated)] - fn to_object(&mut self) -> result::Result, Box> { + fn to_object(&mut self) -> result::Result> { Throwable::to_object(self.deref_mut()) } } @@ -158,8 +155,7 @@ impl Throwable for Infallible { match *self {} } - #[allow(deprecated)] - fn to_object(&mut self) -> result::Result, Box> { + fn to_object(&mut self) -> result::Result> { match *self {} } } @@ -278,7 +274,7 @@ impl Throwable for Error { } } - fn to_object(&mut self) -> result::Result, Box> { + fn to_object(&mut self) -> result::Result> { match self { Error::Io(e) => Throwable::to_object(e as &mut dyn error::Error), Error::Utf8(e) => Throwable::to_object(e as &mut dyn error::Error), @@ -296,13 +292,13 @@ impl Throwable for Error { /// Wrapper of Throwable object. #[derive(Debug)] -pub struct ThrowObject(EBox); +pub struct ThrowObject(ZObject); impl ThrowObject { /// Construct from Throwable object. /// /// Failed if the object is not instance of php `Throwable`. - pub fn new(obj: EBox) -> result::Result { + pub fn new(obj: ZObject) -> result::Result { if !obj.get_class().is_instance_of(throwable_class()) { return Err(NotImplementThrowableError); } @@ -322,7 +318,7 @@ impl ThrowObject { Self::from_result(Throwable::to_object(e)) } - fn from_result(mut result: result::Result, Box>) -> Self { + fn from_result(mut result: result::Result>) -> Self { let mut i = 0; let obj = loop { @@ -343,7 +339,7 @@ impl ThrowObject { /// Consumes the `ThrowObject`, returning the wrapped object. #[inline] - pub fn into_inner(self) -> EBox { + pub fn into_inner(self) -> ZObject { self.0 } @@ -390,7 +386,7 @@ impl Throwable for ThrowObject { } #[inline] - fn to_object(&mut self) -> result::Result, Box> { + fn to_object(&mut self) -> result::Result> { Ok(self.0.to_ref_owned()) } } From 26222490726dc3ae2227dffa8dcaf5a7ce1629b2 Mon Sep 17 00:00:00 2001 From: jmjoy Date: Thu, 5 Jun 2025 22:42:45 +0800 Subject: [PATCH 3/6] refactor: update imports to include ZArray in multiple files and remove unused Drop implementation --- examples/hello/src/lib.rs | 4 +++- examples/http-server/src/server.rs | 1 + examples/http-server/tests/integration.rs | 2 ++ phper/src/objects.rs | 8 -------- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/examples/hello/src/lib.rs b/examples/hello/src/lib.rs index 44b4f68c..fed278e4 100644 --- a/examples/hello/src/lib.rs +++ b/examples/hello/src/lib.rs @@ -8,7 +8,9 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. -use phper::{echo, functions::Argument, modules::Module, php_get_module, values::ZVal}; +use phper::{ + arrays::ZArray, echo, functions::Argument, modules::Module, php_get_module, values::ZVal, +}; /// The php function, receive arguments with type `ZVal`. fn say_hello(arguments: &mut [ZVal]) -> phper::Result<()> { diff --git a/examples/http-server/src/server.rs b/examples/http-server/src/server.rs index d6554569..11a72244 100644 --- a/examples/http-server/src/server.rs +++ b/examples/http-server/src/server.rs @@ -17,6 +17,7 @@ use axum::{ }; use phper::{ alloc::ToRefOwned, + arrays::ZArray, classes::{ClassEntity, Visibility}, functions::Argument, values::ZVal, diff --git a/examples/http-server/tests/integration.rs b/examples/http-server/tests/integration.rs index 9a798e52..39280067 100644 --- a/examples/http-server/tests/integration.rs +++ b/examples/http-server/tests/integration.rs @@ -17,6 +17,7 @@ use std::{ thread::sleep, time::Duration, }; +use hyper::StatusCode; #[test] fn test_php() { @@ -39,6 +40,7 @@ fn test_php() { let client = Client::new(); for _ in 0..5 { let response = client.get("http://127.0.0.1:9000/").send().unwrap(); + assert_eq!(response.status(), StatusCode::OK); let content_type = response.headers().get(CONTENT_TYPE).unwrap(); assert_eq!(content_type, "text/plain"); let body = response.text().unwrap(); diff --git a/phper/src/objects.rs b/phper/src/objects.rs index 2a9bd591..4cd6bcc7 100644 --- a/phper/src/objects.rs +++ b/phper/src/objects.rs @@ -407,14 +407,6 @@ impl StateObj { } } -impl Drop for StateObj { - fn drop(&mut self) { - unsafe { - phper_zend_object_release(self.as_mut_ptr()); - } - } -} - impl Deref for StateObj { type Target = ZObj; From 467c327a4528e4450948e1f2d29e55824777e75e Mon Sep 17 00:00:00 2001 From: jmjoy Date: Thu, 5 Jun 2025 22:46:06 +0800 Subject: [PATCH 4/6] refactor: remove unused ZArray imports from multiple files --- examples/hello/src/lib.rs | 4 +--- examples/http-server/src/server.rs | 1 - examples/http-server/tests/integration.rs | 2 +- phper-doc/doc/_05_internal_types/_01_z_str/index.md | 2 +- 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/examples/hello/src/lib.rs b/examples/hello/src/lib.rs index fed278e4..44b4f68c 100644 --- a/examples/hello/src/lib.rs +++ b/examples/hello/src/lib.rs @@ -8,9 +8,7 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. -use phper::{ - arrays::ZArray, echo, functions::Argument, modules::Module, php_get_module, values::ZVal, -}; +use phper::{echo, functions::Argument, modules::Module, php_get_module, values::ZVal}; /// The php function, receive arguments with type `ZVal`. fn say_hello(arguments: &mut [ZVal]) -> phper::Result<()> { diff --git a/examples/http-server/src/server.rs b/examples/http-server/src/server.rs index 11a72244..d6554569 100644 --- a/examples/http-server/src/server.rs +++ b/examples/http-server/src/server.rs @@ -17,7 +17,6 @@ use axum::{ }; use phper::{ alloc::ToRefOwned, - arrays::ZArray, classes::{ClassEntity, Visibility}, functions::Argument, values::ZVal, diff --git a/examples/http-server/tests/integration.rs b/examples/http-server/tests/integration.rs index 39280067..607796ca 100644 --- a/examples/http-server/tests/integration.rs +++ b/examples/http-server/tests/integration.rs @@ -9,6 +9,7 @@ // See the Mulan PSL v2 for more details. use axum::http::header::CONTENT_TYPE; +use hyper::StatusCode; use phper_test::{cli::test_long_term_php_script_with_condition, utils::get_lib_path}; use reqwest::blocking::Client; use std::{ @@ -17,7 +18,6 @@ use std::{ thread::sleep, time::Duration, }; -use hyper::StatusCode; #[test] fn test_php() { diff --git a/phper-doc/doc/_05_internal_types/_01_z_str/index.md b/phper-doc/doc/_05_internal_types/_01_z_str/index.md index 501a9d4e..ab463ede 100644 --- a/phper-doc/doc/_05_internal_types/_01_z_str/index.md +++ b/phper-doc/doc/_05_internal_types/_01_z_str/index.md @@ -18,7 +18,7 @@ use phper::strings::ZString; let s = ZString::new("Hello world!"); // Will leak memory. -let ptr = s.into_raw(); +let ptr = ZString::into_raw(s); // retake pointer. let ss = unsafe { ZString::from_raw(ptr) }; From 2fb9bf8fdb1228f35241bea52e190f88cb14158c Mon Sep 17 00:00:00 2001 From: jmjoy Date: Fri, 6 Jun 2025 00:14:44 +0800 Subject: [PATCH 5/6] refactor: update documentation attributes and improve copyright comments in multiple files --- phper-test/src/context.rs | 1 - phper-test/src/lib.rs | 2 +- phper/src/alloc.rs | 10 ++++++++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/phper-test/src/context.rs b/phper-test/src/context.rs index 269183f5..97ad26a8 100644 --- a/phper-test/src/context.rs +++ b/phper-test/src/context.rs @@ -82,7 +82,6 @@ impl Context { ContextCommand { cmd, args } } - #[cfg_attr(docsrs, doc(cfg(feature = "fpm")))] pub fn find_php_fpm(&self) -> Option { use std::ffi::OsStr; diff --git a/phper-test/src/lib.rs b/phper-test/src/lib.rs index e775c878..c6cbfe97 100644 --- a/phper-test/src/lib.rs +++ b/phper-test/src/lib.rs @@ -10,7 +10,7 @@ #![warn(rust_2018_idioms, missing_docs)] #![warn(clippy::dbg_macro, clippy::print_stdout)] -#![cfg_attr(docsrs, feature(doc_cfg))] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] #![doc = include_str!("../README.md")] pub mod cli; diff --git a/phper/src/alloc.rs b/phper/src/alloc.rs index abf1d6eb..f6bb4da3 100644 --- a/phper/src/alloc.rs +++ b/phper/src/alloc.rs @@ -1,3 +1,13 @@ +// Copyright (c) 2025 PHPER Framework Team +// PHPER is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + //! Memory allocation utilities and boxed types for PHP values. pub use phper_alloc::{RefClone, ToRefOwned}; From f468861a8b727e19dfdbedd588c0a2a5622a5a3e Mon Sep 17 00:00:00 2001 From: jmjoy Date: Fri, 6 Jun 2025 00:26:41 +0800 Subject: [PATCH 6/6] refactor: simplify byte slice comparison in ZString implementation --- phper/src/strings.rs | 3 +-- tests/integration/src/strings.rs | 6 ++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/phper/src/strings.rs b/phper/src/strings.rs index 1b16abef..62d73aba 100644 --- a/phper/src/strings.rs +++ b/phper/src/strings.rs @@ -235,8 +235,7 @@ impl AsRef<[u8]> for ZString { impl> PartialEq for ZString { fn eq(&self, other: &Rhs) -> bool { - let this: &[u8] = self.as_ref(); - this == other.as_ref() + AsRef::<[u8]>::as_ref(self) == other.as_ref() } } diff --git a/tests/integration/src/strings.rs b/tests/integration/src/strings.rs index b95fd926..7ec691d7 100644 --- a/tests/integration/src/strings.rs +++ b/tests/integration/src/strings.rs @@ -18,8 +18,7 @@ pub fn integrate(module: &mut Module) { assert_eq!(zs.to_str()?, "hello"); let zs = ZString::new([1, 2, 3]); - let zs: &[u8] = zs.as_ref(); - assert_eq!(zs, &[1, 2, 3]); + assert_eq!(AsRef::<[u8]>::as_ref(&zs), &[1, 2, 3]); assert!(ZString::new("hello") == ZString::new(b"hello")); @@ -34,8 +33,7 @@ pub fn integrate(module: &mut Module) { assert_eq!(zs.to_str()?, "persistent_hello"); let zs = ZString::new_persistent([4, 5, 6]); - let zs: &[u8] = zs.as_ref(); - assert_eq!(zs, &[4, 5, 6]); + assert_eq!(AsRef::<[u8]>::as_ref(&zs), &[4, 5, 6]); assert!( ZString::new_persistent("persistent") == ZString::new_persistent(b"persistent")