@@ -28,7 +28,7 @@ use std::{
2828 ffi:: { c_void, CString } ,
2929 fmt:: Debug ,
3030 marker:: PhantomData ,
31- mem:: { size_of, zeroed, ManuallyDrop } ,
31+ mem:: { replace , size_of, zeroed, ManuallyDrop } ,
3232 os:: raw:: c_int,
3333 ptr:: null_mut,
3434 rc:: Rc ,
@@ -181,6 +181,37 @@ impl ClassEntry {
181181 pub fn is_instance_of ( & self , parent : & ClassEntry ) -> bool {
182182 unsafe { phper_instanceof_function ( self . as_ptr ( ) , parent. as_ptr ( ) ) }
183183 }
184+
185+ /// Get the static property by name of class.
186+ ///
187+ /// Return None when static property hasn't register by
188+ /// [ClassEntity::add_static_property].
189+ pub fn get_static_property ( & self , name : impl AsRef < str > ) -> Option < & ZVal > {
190+ let ptr = self . as_ptr ( ) as * mut _ ;
191+ let prop = Self :: inner_get_static_property ( ptr, name) ;
192+ unsafe { ZVal :: try_from_ptr ( prop) }
193+ }
194+
195+ /// Set the static property by name of class.
196+ ///
197+ /// Return `Some(x)` where `x` is the previous value of static property, or
198+ /// return `None` when static property hasn't register by
199+ /// [ClassEntity::add_static_property].
200+ pub fn set_static_property ( & self , name : impl AsRef < str > , val : impl Into < ZVal > ) -> Option < ZVal > {
201+ let ptr = self . as_ptr ( ) as * mut _ ;
202+ let prop = Self :: inner_get_static_property ( ptr, name) ;
203+ let prop = unsafe { ZVal :: try_from_mut_ptr ( prop) } ;
204+ prop. map ( |prop| replace ( prop, val. into ( ) ) )
205+ }
206+
207+ fn inner_get_static_property ( scope : * mut zend_class_entry , name : impl AsRef < str > ) -> * mut zval {
208+ let name = name. as_ref ( ) ;
209+
210+ unsafe {
211+ #[ allow( clippy:: useless_conversion) ]
212+ zend_read_static_property ( scope, name. as_ptr ( ) . cast ( ) , name. len ( ) , true . into ( ) )
213+ }
214+ }
184215}
185216
186217impl Debug for ClassEntry {
@@ -444,6 +475,19 @@ impl<T: 'static> ClassEntity<T> {
444475 . push ( PropertyEntity :: new ( name, visibility, value) ) ;
445476 }
446477
478+ /// Declare static property.
479+ ///
480+ /// The argument `value` should be `Copy` because 'zend_declare_property'
481+ /// receive only scalar zval , otherwise will report fatal error:
482+ /// "Internal zvals cannot be refcounted".
483+ pub fn add_static_property (
484+ & mut self , name : impl Into < String > , visibility : Visibility , value : impl Into < Scalar > ,
485+ ) {
486+ let mut entity = PropertyEntity :: new ( name, visibility, value) ;
487+ entity. set_vis_static ( ) ;
488+ self . property_entities . push ( entity) ;
489+ }
490+
447491 /// Register class to `extends` the parent class.
448492 ///
449493 /// *Because in the `MINIT` phase, the class starts to register, so the*
@@ -719,24 +763,30 @@ unsafe extern "C" fn interface_init_handler(
719763/// Builder for declare class property.
720764struct PropertyEntity {
721765 name : String ,
722- visibility : Visibility ,
766+ visibility : RawVisibility ,
723767 value : Scalar ,
724768}
725769
726770impl PropertyEntity {
727771 fn new ( name : impl Into < String > , visibility : Visibility , value : impl Into < Scalar > ) -> Self {
728772 Self {
729773 name : name. into ( ) ,
730- visibility,
774+ visibility : visibility as RawVisibility ,
731775 value : value. into ( ) ,
732776 }
733777 }
734778
779+ #[ inline]
780+ pub ( crate ) fn set_vis_static ( & mut self ) -> & mut Self {
781+ self . visibility |= ZEND_ACC_STATIC ;
782+ self
783+ }
784+
735785 #[ allow( clippy:: useless_conversion) ]
736786 pub ( crate ) fn declare ( & self , ce : * mut zend_class_entry ) {
737787 let name = self . name . as_ptr ( ) . cast ( ) ;
738788 let name_length = self . name . len ( ) . try_into ( ) . unwrap ( ) ;
739- let access_type = self . visibility as u32 as i32 ;
789+ let access_type = self . visibility as i32 ;
740790
741791 unsafe {
742792 match & self . value {
0 commit comments