@@ -28,7 +28,7 @@ use std::{
2828 ffi:: { CString , c_char, c_void} ,
2929 fmt:: Debug ,
3030 marker:: PhantomData ,
31- mem:: { ManuallyDrop , replace, size_of, zeroed} ,
31+ mem:: { ManuallyDrop , replace, size_of, transmute , zeroed} ,
3232 os:: raw:: c_int,
3333 ptr,
3434 ptr:: null_mut,
@@ -287,13 +287,26 @@ fn find_global_class_entry_ptr(name: impl AsRef<str>) -> *mut zend_class_entry {
287287/// ```
288288pub struct StateClass < T > {
289289 inner : Rc < RefCell < * mut zend_class_entry > > ,
290+ name : Option < String > ,
290291 _p : PhantomData < T > ,
291292}
292293
294+ impl StateClass < ( ) > {
295+ /// Create from name, which will be looked up from globals.
296+ pub fn from_name ( name : impl Into < String > ) -> Self {
297+ Self {
298+ inner : Rc :: new ( RefCell :: new ( null_mut ( ) ) ) ,
299+ name : Some ( name. into ( ) ) ,
300+ _p : PhantomData ,
301+ }
302+ }
303+ }
304+
293305impl < T > StateClass < T > {
294306 fn null ( ) -> Self {
295307 Self {
296308 inner : Rc :: new ( RefCell :: new ( null_mut ( ) ) ) ,
309+ name : None ,
297310 _p : PhantomData ,
298311 }
299312 }
@@ -304,7 +317,11 @@ impl<T> StateClass<T> {
304317
305318 /// Converts to class entry.
306319 pub fn as_class_entry ( & self ) -> & ClassEntry {
307- unsafe { ClassEntry :: from_mut_ptr ( * self . inner . borrow ( ) ) }
320+ if let Some ( name) = & self . name {
321+ ClassEntry :: from_globals ( name) . unwrap ( )
322+ } else {
323+ unsafe { ClassEntry :: from_mut_ptr ( * self . inner . borrow ( ) ) }
324+ }
308325 }
309326
310327 /// Create the object from class and call `__construct` with arguments.
@@ -333,6 +350,7 @@ impl<T> Clone for StateClass<T> {
333350 fn clone ( & self ) -> Self {
334351 Self {
335352 inner : self . inner . clone ( ) ,
353+ name : self . name . clone ( ) ,
336354 _p : self . _p ,
337355 }
338356 }
@@ -427,7 +445,7 @@ pub struct ClassEntity<T: 'static> {
427445 state_constructor : Rc < StateConstructor > ,
428446 method_entities : Vec < MethodEntity > ,
429447 property_entities : Vec < PropertyEntity > ,
430- parent : Option < Box < dyn Fn ( ) -> & ' static ClassEntry > > ,
448+ parent : Option < StateClass < ( ) > > ,
431449 interfaces : Vec < Interface > ,
432450 constants : Vec < ConstantEntity > ,
433451 bind_class : StateClass < T > ,
@@ -557,7 +575,7 @@ impl<T: 'static> ClassEntity<T> {
557575 ///
558576 /// ```no_run
559577 /// use phper::{
560- /// classes::{ClassEntity, ClassEntry},
578+ /// classes::{ClassEntity, ClassEntry, StateClass },
561579 /// modules::Module,
562580 /// php_get_module,
563581 /// };
@@ -572,38 +590,18 @@ impl<T: 'static> ClassEntity<T> {
572590 ///
573591 /// let foo = module.add_class(ClassEntity::new("Foo"));
574592 /// let mut bar = ClassEntity::new("Bar");
575- /// bar.extends(&foo);
593+ /// bar.extends(foo);
594+ /// module.add_class(bar);
595+ ///
596+ /// let mut ex = ClassEntity::new("MyException");
597+ /// ex.extends(StateClass::from_name("Exception"));
598+ /// module.add_class(ex);
576599 ///
577600 /// module
578601 /// }
579602 /// ```
580- pub fn extends < U : ' static > ( & mut self , parent : & StateClass < U > ) {
581- let parent = parent. clone ( ) ;
582- self . parent = Some ( Box :: new ( move || {
583- let entry: & ' static ClassEntry =
584- unsafe { std:: mem:: transmute ( parent. as_class_entry ( ) ) } ;
585- entry
586- } ) ) ;
587- }
588-
589- /// Register class to `extends` the parent class, by name. Similar to
590- /// `extends`, this is useful for built-ins.
591- ///
592- /// # Examples
593- ///
594- /// ```no_run
595- /// use phper::classes::{ClassEntity, ClassEntry};
596- ///
597- /// let mut class = ClassEntity::new("MyException");
598- /// class.extends_name("Exception");
599- /// ```
600- pub fn extends_name ( & mut self , name : impl Into < String > ) {
601- let name = name. into ( ) ;
602- self . parent = Some ( Box :: new ( move || {
603- ClassEntry :: from_globals ( & name) . unwrap_or_else ( |_| {
604- panic ! ( "Unable to resolve parent class: {}" , name) ;
605- } )
606- } ) ) ;
603+ pub fn extends < S : ' static > ( & mut self , parent : StateClass < S > ) {
604+ self . parent = Some ( unsafe { transmute :: < StateClass < S > , StateClass < ( ) > > ( parent) } ) ;
607605 }
608606
609607 /// Register class to `implements` the interface, due to the class can
@@ -672,11 +670,12 @@ impl<T: 'static> ClassEntity<T> {
672670 #[ allow( clippy:: useless_conversion) ]
673671 pub ( crate ) unsafe fn init ( & self ) -> * mut zend_class_entry {
674672 unsafe {
675- let parent: * mut zend_class_entry = if let Some ( ref parent_fn) = self . parent {
676- parent_fn ( ) . as_ptr ( ) as * mut _
677- } else {
678- null_mut ( )
679- } ;
673+ let parent: * mut zend_class_entry = self
674+ . parent
675+ . as_ref ( )
676+ . map ( |parent| parent. as_class_entry ( ) )
677+ . map ( |entry| entry. as_ptr ( ) as * mut _ )
678+ . unwrap_or ( null_mut ( ) ) ;
680679
681680 let class_ce = phper_init_class_entry_ex (
682681 self . class_name . as_ptr ( ) . cast ( ) ,
0 commit comments