@@ -376,22 +376,39 @@ impl<T> Clone for StateClass<T> {
376
376
#[ derive( Clone ) ]
377
377
pub struct Interface {
378
378
inner : Rc < RefCell < * mut zend_class_entry > > ,
379
+ name : Option < String > ,
379
380
}
380
381
381
382
impl Interface {
382
383
fn null ( ) -> Self {
383
384
Self {
384
385
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 ( ) ) ,
385
395
}
386
396
}
387
397
388
398
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
+ }
389
402
* self . inner . borrow_mut ( ) = ptr;
390
403
}
391
404
392
405
/// Converts to class entry.
393
406
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
+ }
395
412
}
396
413
}
397
414
@@ -411,7 +428,7 @@ pub struct ClassEntity<T: 'static> {
411
428
method_entities : Vec < MethodEntity > ,
412
429
property_entities : Vec < PropertyEntity > ,
413
430
parent : Option < Box < dyn Fn ( ) -> & ' static ClassEntry > > ,
414
- interfaces : Vec < Box < dyn Fn ( ) -> & ' static ClassEntry > > ,
431
+ interfaces : Vec < Interface > ,
415
432
constants : Vec < ConstantEntity > ,
416
433
bind_class : StateClass < T > ,
417
434
state_cloner : Option < Rc < StateCloner > > ,
@@ -552,23 +569,22 @@ impl<T: 'static> ClassEntity<T> {
552
569
/// implement multi interface, so this method can be called multi time.
553
570
///
554
571
/// *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*
557
573
///
558
574
/// # Examples
559
575
///
560
576
/// ```no_run
561
- /// use phper::classes::{ClassEntity, ClassEntry};
577
+ /// use phper::classes::{ClassEntity, ClassEntry, Interface };
562
578
///
563
579
/// let mut class = ClassEntity::new("MyClass");
564
- /// class.implements(|| ClassEntry::from_globals ("Stringable").unwrap( ));
580
+ /// class.implements(Interface::from_name ("Stringable"));
565
581
///
566
582
/// // Here you have to the implement the method `__toString()` in `Stringable`
567
583
/// // for `MyClass`, otherwise `MyClass` will become abstract class.
568
584
/// // ...
569
585
/// ```
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) ;
572
588
}
573
589
574
590
/// Add the state clone function, called when cloning PHP object.
@@ -633,7 +649,7 @@ impl<T: 'static> ClassEntity<T> {
633
649
self . bind_class . bind ( class_ce) ;
634
650
635
651
for interface in & self . interfaces {
636
- let interface_ce = interface ( ) . as_ptr ( ) ;
652
+ let interface_ce = interface. as_class_entry ( ) . as_ptr ( ) ;
637
653
zend_class_implements ( class_ce, 1 , interface_ce) ;
638
654
}
639
655
0 commit comments