@@ -376,22 +376,39 @@ impl<T> Clone for StateClass<T> {
376376#[ derive( Clone ) ]
377377pub struct Interface {
378378 inner : Rc < RefCell < * mut zend_class_entry > > ,
379+ name : Option < String > ,
379380}
380381
381382impl Interface {
382383 fn null ( ) -> Self {
383384 Self {
384385 inner : Rc :: new ( RefCell :: new ( null_mut ( ) ) ) ,
386+ name : None ,
387+ }
388+ }
389+
390+ /// Create a new interface from global name (eg "Stringable", "ArrayAccess")
391+ pub fn from_name ( name : impl Into < String > ) -> Self {
392+ Self {
393+ inner : Rc :: new ( RefCell :: new ( null_mut ( ) ) ) ,
394+ name : Some ( name. into ( ) ) ,
385395 }
386396 }
387397
388398 fn bind ( & self , ptr : * mut zend_class_entry ) {
399+ if self . name . is_some ( ) {
400+ panic ! ( "Cannot bind() an Interface created with from_name()" ) ;
401+ }
389402 * self . inner . borrow_mut ( ) = ptr;
390403 }
391404
392405 /// Converts to class entry.
393406 pub fn as_class_entry ( & self ) -> & ClassEntry {
394- unsafe { ClassEntry :: from_mut_ptr ( * self . inner . borrow ( ) ) }
407+ if let Some ( name) = & self . name {
408+ ClassEntry :: from_globals ( name) . unwrap ( )
409+ } else {
410+ unsafe { ClassEntry :: from_mut_ptr ( * self . inner . borrow ( ) ) }
411+ }
395412 }
396413}
397414
@@ -411,7 +428,7 @@ pub struct ClassEntity<T: 'static> {
411428 method_entities : Vec < MethodEntity > ,
412429 property_entities : Vec < PropertyEntity > ,
413430 parent : Option < Box < dyn Fn ( ) -> & ' static ClassEntry > > ,
414- interfaces : Vec < Box < dyn Fn ( ) -> & ' static ClassEntry > > ,
431+ interfaces : Vec < Interface > ,
415432 constants : Vec < ConstantEntity > ,
416433 bind_class : StateClass < T > ,
417434 state_cloner : Option < Rc < StateCloner > > ,
@@ -552,23 +569,22 @@ impl<T: 'static> ClassEntity<T> {
552569 /// implement multi interface, so this method can be called multi time.
553570 ///
554571 /// *Because in the `MINIT` phase, the class starts to register, so the*
555- /// *closure is used to return the `ClassEntry` to delay the acquisition of*
556- /// *the class.*
572+ /// *`ClassEntry` is not fetched until later*
557573 ///
558574 /// # Examples
559575 ///
560576 /// ```no_run
561- /// use phper::classes::{ClassEntity, ClassEntry};
577+ /// use phper::classes::{ClassEntity, ClassEntry, Interface };
562578 ///
563579 /// let mut class = ClassEntity::new("MyClass");
564- /// class.implements(|| ClassEntry::from_globals ("Stringable").unwrap( ));
580+ /// class.implements(Interface::from_name ("Stringable"));
565581 ///
566582 /// // Here you have to the implement the method `__toString()` in `Stringable`
567583 /// // for `MyClass`, otherwise `MyClass` will become abstract class.
568584 /// // ...
569585 /// ```
570- pub fn implements ( & mut self , interface : impl Fn ( ) -> & ' static ClassEntry + ' static ) {
571- self . interfaces . push ( Box :: new ( interface) ) ;
586+ pub fn implements ( & mut self , interface : Interface ) {
587+ self . interfaces . push ( interface) ;
572588 }
573589
574590 /// Add the state clone function, called when cloning PHP object.
@@ -633,7 +649,7 @@ impl<T: 'static> ClassEntity<T> {
633649 self . bind_class . bind ( class_ce) ;
634650
635651 for interface in & self . interfaces {
636- let interface_ce = interface ( ) . as_ptr ( ) ;
652+ let interface_ce = interface. as_class_entry ( ) . as_ptr ( ) ;
637653 zend_class_implements ( class_ce, 1 , interface_ce) ;
638654 }
639655
0 commit comments