Skip to content

Commit 4b29427

Browse files
committed
extends(StateClass)
import ClassEntity::extends(StateClass) code from jmjoy:phper-fork:extends
1 parent 91d9bfd commit 4b29427

File tree

6 files changed

+49
-50
lines changed

6 files changed

+49
-50
lines changed

examples/http-client/src/errors.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
// See the Mulan PSL v2 for more details.
1010

1111
use phper::{
12-
classes::{ClassEntity, ClassEntry},
12+
classes::{ClassEntity, ClassEntry, StateClass},
1313
errors::{Throwable, exception_class},
1414
};
1515

@@ -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_name("Exception");
22+
class.extends(StateClass::from_name("Exception"));
2323
class
2424
}
2525

examples/http-server/src/errors.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
// See the Mulan PSL v2 for more details.
1010

1111
use phper::{
12-
classes::{ClassEntity, ClassEntry},
12+
classes::{ClassEntity, ClassEntry, StateClass},
1313
errors::{Throwable, exception_class},
1414
};
1515
use std::error::Error;
@@ -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_name("Exception");
46+
class.extends(StateClass::from_name("Exception"));
4747
class
4848
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ Now let's begin to finish the logic.
9191

9292
```rust
9393
use phper::{
94-
classes::{ClassEntry, ClassEntity},
94+
classes::{ClassEntry, ClassEntity, StateClass},
9595
errors::{exception_class, Throwable},
9696
};
9797

@@ -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_name("Exception");
104+
class.extends(StateClass::from_name("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_name("Exception");
158+
# class.extends(StateClass::from_name("Exception"));
159159
# class
160160
# }
161161
#

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,16 @@ class Foo {}
3939
## Extends & implements
4040

4141
To allow a class to extend another, you can either use `ClassEntity.extends(StateClass<T>)` for classes implemented
42-
in your module, or `ClassEntity.extends_name(String)` for built-ins (although, `extends_name` should actually work
43-
for any class).
42+
in your module.
4443

45-
If you want the class `Foo` extends `Bar`, and implements interface `Stringable`:
44+
If you want class `Foo` extends `Bar`, and implements interface `Stringable`:
4645

4746
```rust,no_run
4847
use phper::classes::{ClassEntity, ClassEntry, Interface};
4948
49+
let mut bar = ClassEntity::new("Bar").bind_class();
5050
let mut foo = ClassEntity::new("Foo");
51-
foo.extends_name("Bar");
51+
foo.extends(bar);
5252
foo.implements(Interface::from_name("Stringable"));
5353
```
5454

phper/src/classes.rs

Lines changed: 36 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -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
/// ```
288288
pub 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+
293305
impl<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(),

tests/integration/src/classes.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ pub fn integrate(module: &mut Module) {
2424
integrate_i_bar(module);
2525
integrate_static_props(module);
2626
integrate_i_constants(module);
27-
integrate_bar_extends_foo(module, &foo_class);
27+
integrate_bar_extends_foo(module, foo_class);
2828
#[cfg(phper_major_version = "8")]
2929
integrate_stringable(module);
3030
}
@@ -222,7 +222,7 @@ fn integrate_static_props(module: &mut Module) {
222222
module.add_class(class);
223223
}
224224

225-
fn integrate_bar_extends_foo(module: &mut Module, foo_class: &StateClass<Foo>) {
225+
fn integrate_bar_extends_foo(module: &mut Module, foo_class: StateClass<Foo>) {
226226
let mut cls = ClassEntity::new(r"IntegrationTest\BarExtendsFoo");
227227
cls.extends(foo_class);
228228
cls.add_method("test", Visibility::Public, |_, _| phper::ok(()));

0 commit comments

Comments
 (0)