Skip to content

Commit 40c3503

Browse files
committed
improve ClassEntry::extends
instead of accepting a fn to delay fetching ClassEntry, accept a String and look up during init()
1 parent bdf7caa commit 40c3503

File tree

7 files changed

+34
-17
lines changed

7 files changed

+34
-17
lines changed

examples/http-client/src/errors.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const EXCEPTION_CLASS_NAME: &str = "HttpClient\\HttpClientException";
1919
pub fn make_exception_class() -> ClassEntity<()> {
2020
let mut class = ClassEntity::new(EXCEPTION_CLASS_NAME);
2121
// The `extends` is same as the PHP class `extends`.
22-
class.extends(exception_class);
22+
class.extends("Exception");
2323
class
2424
}
2525

examples/http-server/src/errors.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,6 @@ impl From<HttpServerError> for phper::Error {
4343
pub fn make_exception_class() -> ClassEntity<()> {
4444
let mut class = ClassEntity::new(EXCEPTION_CLASS_NAME);
4545
// As an Exception class, inheriting from the base Exception class is important.
46-
class.extends(exception_class);
46+
class.extends("Exception");
4747
class
4848
}

phper-doc/doc/_02_quick_start/_02_write_a_simple_http_client/index.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ Now let's begin to finish the logic.
101101
pub fn make_exception_class() -> ClassEntity<()> {
102102
let mut class = ClassEntity::new(EXCEPTION_CLASS_NAME);
103103
// The `extends` is same as the PHP class `extends`.
104-
class.extends(exception_class);
104+
class.extends("Exception");
105105
class
106106
}
107107

@@ -155,7 +155,7 @@ Now let's begin to finish the logic.
155155
# pub fn make_exception_class() -> ClassEntity<()> {
156156
# let mut class = ClassEntity::new(EXCEPTION_CLASS_NAME);
157157
# // The `extends` is same as the PHP class `extends`.
158-
# class.extends(exception_class);
158+
# class.extends("Exception");
159159
# class
160160
# }
161161
#

phper-doc/doc/_06_module/_06_register_class/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ If you want the class `Foo` extends `Bar`, and implements interface `Stringable`
4444
use phper::classes::{ClassEntity, ClassEntry, Interface};
4545
4646
let mut foo = ClassEntity::new("Foo");
47-
foo.extends(|| ClassEntry::from_globals("Bar").unwrap());
47+
foo.extends("Bar");
4848
foo.implements(Interface::from_name("Stringable"));
4949
```
5050

phper/src/classes.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,7 @@ pub struct ClassEntity<T: 'static> {
427427
state_constructor: Rc<StateConstructor>,
428428
method_entities: Vec<MethodEntity>,
429429
property_entities: Vec<PropertyEntity>,
430-
parent: Option<Box<dyn Fn() -> &'static ClassEntry>>,
430+
parent: Option<String>,
431431
interfaces: Vec<Interface>,
432432
constants: Vec<ConstantEntity>,
433433
bind_class: StateClass<T>,
@@ -550,7 +550,7 @@ impl<T: 'static> ClassEntity<T> {
550550
/// Register class to `extends` the parent class.
551551
///
552552
/// *Because in the `MINIT` phase, the class starts to register, so the*
553-
/// *closure is used to return the `ClassEntry` to delay the acquisition of*
553+
/// *`ClassEntry` is looked up by name to delay the acquisition of*
554554
/// *the class.*
555555
///
556556
/// # Examples
@@ -559,10 +559,10 @@ impl<T: 'static> ClassEntity<T> {
559559
/// use phper::classes::{ClassEntity, ClassEntry};
560560
///
561561
/// let mut class = ClassEntity::new("MyException");
562-
/// class.extends(|| ClassEntry::from_globals("Exception").unwrap());
562+
/// class.extends("Exception");
563563
/// ```
564-
pub fn extends(&mut self, parent: impl Fn() -> &'static ClassEntry + 'static) {
565-
self.parent = Some(Box::new(parent));
564+
pub fn extends(&mut self, parent_name: impl Into<String>) {
565+
self.parent = Some(parent_name.into());
566566
}
567567

568568
/// Register class to `implements` the interface, due to the class can
@@ -631,12 +631,14 @@ impl<T: 'static> ClassEntity<T> {
631631
#[allow(clippy::useless_conversion)]
632632
pub(crate) unsafe fn init(&self) -> *mut zend_class_entry {
633633
unsafe {
634-
let parent: *mut zend_class_entry = self
635-
.parent
636-
.as_ref()
637-
.map(|parent| parent())
638-
.map(|entry| entry.as_ptr() as *mut _)
639-
.unwrap_or(null_mut());
634+
let parent: *mut zend_class_entry = if let Some(ref name) = self.parent {
635+
let entry = ClassEntry::from_globals(name).unwrap_or_else(|err| {
636+
panic!("Unable to resolve parent class: {}: {}", name,err);
637+
});
638+
entry.as_ptr() as *mut _
639+
} else {
640+
null_mut()
641+
};
640642

641643
let class_ce = phper_init_class_entry_ex(
642644
self.class_name.as_ptr().cast(),
@@ -800,7 +802,7 @@ impl InterfaceEntity {
800802
/// Register interface to `extends` the interfaces, due to the interface can
801803
/// extends multi interface, so this method can be called multi time.
802804
///
803-
/// *Because in the `MINIT` phase, the class starts to register, so the*
805+
/// *Because in the `MINIT` phase, the class starts to register, a*
804806
/// *closure is used to return the `ClassEntry` to delay the acquisition of*
805807
/// *the class.*
806808
///

tests/integration/src/classes.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ pub fn integrate(module: &mut Module) {
2626
integrate_i_bar(module);
2727
integrate_static_props(module);
2828
integrate_i_constants(module);
29+
integrate_bar_extends_foo(module);
2930
#[cfg(phper_major_version = "8")]
3031
integrate_stringable(module);
3132
}
@@ -223,6 +224,15 @@ fn integrate_static_props(module: &mut Module) {
223224
module.add_class(class);
224225
}
225226

227+
fn integrate_bar_extends_foo(module: &mut Module) {
228+
let mut cls = ClassEntity::new(r"IntegrationTest\BarExtendsFoo");
229+
cls.extends(r"IntegrationTest\Foo");
230+
cls.add_method("test", Visibility::Public, |_,_| {
231+
phper::ok(())
232+
});
233+
module.add_class(cls);
234+
}
235+
226236
#[cfg(phper_major_version = "8")]
227237
fn integrate_stringable(module: &mut Module) {
228238
use phper::{functions::ReturnType, types::ReturnTypeHint};

tests/integration/tests/php/classes.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,3 +100,8 @@ class Foo2 extends IntegrationTest\Foo {}
100100
assert_false(IntegrationTest\IConstants::CST_FALSE);
101101
assert_eq(100, IntegrationTest\IConstants::CST_INT);
102102
assert_eq(10.0, IntegrationTest\IConstants::CST_FLOAT);
103+
104+
// Test module class extends module class
105+
$bar = new \IntegrationTest\BarExtendsFoo; //Bar should extend Foo
106+
$reflection = new ReflectionClass($bar);
107+
assert_true($reflection->isSubclassOf(IntegrationTest\Foo::class));

0 commit comments

Comments
 (0)