Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit477bb83

Browse files
authored
improve Interface::extends and ClassEntry::extends (#190)
1 parenta118552 commit477bb83

File tree

8 files changed

+97
-49
lines changed

8 files changed

+97
-49
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
pubfnmake_exception_class() ->ClassEntity<()>{
2020
letmut class =ClassEntity::new(EXCEPTION_CLASS_NAME);
2121
// The `extends` is same as the PHP class `extends`.
22-
class.extends(exception_class);
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
pubfnmake_exception_class() ->ClassEntity<()>{
4444
letmut 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(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
usephper::{
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
pubfnmake_exception_class()->ClassEntity<()> {
102102
letmutclass=ClassEntity::new(EXCEPTION_CLASS_NAME);
103103
// The `extends` is same as the PHP class `extends`.
104-
class.extends(exception_class);
104+
class.extends(StateClass::from_name("Exception"));
105105
class
106106
}
107107

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

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,21 @@ class Foo {}
3838

3939
##Extends & implements
4040

41-
If you want the class`Foo` extends`Bar`, and implements interface`Stringable`:
41+
To allow a class to extend another, you can use`ClassEntity.extends(StateClass<T>)` for classes implemented
42+
in your module. A StateClass can either be obtained by registering your own class against the module, or
43+
by looking up the class by name (for example, for PHP built-in classes like`Exception`).
44+
45+
If you want class`Foo` extends`Bar`, and implements interface`Stringable`:
4246

4347
```rust,no_run
4448
use phper::classes::{ClassEntity, ClassEntry, Interface};
49+
use phper::{modules::Module, php_get_module};
50+
51+
let mut module = Module::new("test", "0.1", "");
4552
53+
let bar = module.add_class(ClassEntity::new("Bar"));
4654
let mut foo = ClassEntity::new("Foo");
47-
foo.extends(|| ClassEntry::from_globals("Bar").unwrap());
55+
foo.extends(bar);
4856
foo.implements(Interface::from_name("Stringable"));
4957
```
5058

‎phper-doc/doc/_06_module/_07_register_interface/index.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,11 @@ interface Foo {}
4141
If you want the interface`Foo` extends`ArrayAccess` and`Iterator` interfaces.
4242

4343
```rust,no_run
44-
use phper::classes::{InterfaceEntity, ClassEntry};
45-
use phper::classes::{array_access_class, iterator_class};
44+
use phper::classes::{Interface, InterfaceEntity, ClassEntry};
4645
4746
let mut foo = InterfaceEntity::new("Foo");
48-
foo.extends(|| array_access_class());
49-
foo.extends(|| iterator_class());
47+
foo.extends(Interface::from_name("ArrayAccess"));
48+
foo.extends(Interface::from_name("Iterator"));
5049
```
5150

5251
Same as:

‎phper/src/classes.rs

Lines changed: 58 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -28,26 +28,14 @@ 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,
3535
rc::Rc,
3636
slice,
3737
};
3838

39-
/// Predefined interface `Iterator`.
40-
#[inline]
41-
pubfniterator_class<'a>() ->&'aClassEntry{
42-
unsafe{ClassEntry::from_ptr(zend_ce_iterator)}
43-
}
44-
45-
/// Predefined interface `ArrayAccess`.
46-
#[inline]
47-
pubfnarray_access_class<'a>() ->&'aClassEntry{
48-
unsafe{ClassEntry::from_ptr(zend_ce_arrayaccess)}
49-
}
50-
5139
/// Wrapper of [zend_class_entry].
5240
#[derive(Clone)]
5341
#[repr(transparent)]
@@ -287,13 +275,26 @@ fn find_global_class_entry_ptr(name: impl AsRef<str>) -> *mut zend_class_entry {
287275
/// ```
288276
pubstructStateClass<T>{
289277
inner:Rc<RefCell<*mutzend_class_entry>>,
278+
name:Option<String>,
290279
_p:PhantomData<T>,
291280
}
292281

282+
implStateClass<()>{
283+
/// Create from name, which will be looked up from globals.
284+
pubfnfrom_name(name:implInto<String>) ->Self{
285+
Self{
286+
inner:Rc::new(RefCell::new(null_mut())),
287+
name:Some(name.into()),
288+
_p:PhantomData,
289+
}
290+
}
291+
}
292+
293293
impl<T>StateClass<T>{
294294
fnnull() ->Self{
295295
Self{
296296
inner:Rc::new(RefCell::new(null_mut())),
297+
name:None,
297298
_p:PhantomData,
298299
}
299300
}
@@ -304,7 +305,11 @@ impl<T> StateClass<T> {
304305

305306
/// Converts to class entry.
306307
pubfnas_class_entry(&self) ->&ClassEntry{
307-
unsafe{ClassEntry::from_mut_ptr(*self.inner.borrow())}
308+
ifletSome(name) =&self.name{
309+
ClassEntry::from_globals(name).unwrap()
310+
}else{
311+
unsafe{ClassEntry::from_mut_ptr(*self.inner.borrow())}
312+
}
308313
}
309314

310315
/// Create the object from class and call `__construct` with arguments.
@@ -333,6 +338,7 @@ impl<T> Clone for StateClass<T> {
333338
fnclone(&self) ->Self{
334339
Self{
335340
inner:self.inner.clone(),
341+
name:self.name.clone(),
336342
_p:self._p,
337343
}
338344
}
@@ -427,7 +433,7 @@ pub struct ClassEntity<T: 'static> {
427433
state_constructor:Rc<StateConstructor>,
428434
method_entities:Vec<MethodEntity>,
429435
property_entities:Vec<PropertyEntity>,
430-
parent:Option<Box<dynFn() ->&'staticClassEntry>>,
436+
parent:Option<StateClass<()>>,
431437
interfaces:Vec<Interface>,
432438
constants:Vec<ConstantEntity>,
433439
bind_class:StateClass<T>,
@@ -550,19 +556,40 @@ impl<T: 'static> ClassEntity<T> {
550556
/// Register class to `extends` the parent class.
551557
///
552558
/// *Because in the `MINIT` phase, the class starts to register, so the*
553-
/// *closure isused to return the `ClassEntry` to delay the acquisition of*
559+
/// *`ClassEntry` islooked up by name to delay the acquisition of*
554560
/// *the class.*
555561
///
556562
/// # Examples
557563
///
558564
/// ```no_run
559-
/// use phper::classes::{ClassEntity, ClassEntry};
565+
/// use phper::{
566+
/// classes::{ClassEntity, ClassEntry, StateClass},
567+
/// modules::Module,
568+
/// php_get_module,
569+
/// };
560570
///
561-
/// let mut class = ClassEntity::new("MyException");
562-
/// class.extends(|| ClassEntry::from_globals("Exception").unwrap());
571+
/// #[php_get_module]
572+
/// pub fn get_module() -> Module {
573+
/// let mut module = Module::new(
574+
/// env!("CARGO_CRATE_NAME"),
575+
/// env!("CARGO_PKG_VERSION"),
576+
/// env!("CARGO_PKG_AUTHORS"),
577+
/// );
578+
///
579+
/// let foo = module.add_class(ClassEntity::new("Foo"));
580+
/// let mut bar = ClassEntity::new("Bar");
581+
/// bar.extends(foo);
582+
/// module.add_class(bar);
583+
///
584+
/// let mut ex = ClassEntity::new("MyException");
585+
/// ex.extends(StateClass::from_name("Exception"));
586+
/// module.add_class(ex);
587+
///
588+
/// module
589+
/// }
563590
/// ```
564-
pubfnextends(&mutself,parent:implFn() ->&'staticClassEntry +'static){
565-
self.parent =Some(Box::new(parent));
591+
pubfnextends<S:'static>(&mutself,parent:StateClass<S>){
592+
self.parent =Some(unsafe{transmute::<StateClass<S>,StateClass<()>>(parent)});
566593
}
567594

568595
/// Register class to `implements` the interface, due to the class can
@@ -634,7 +661,7 @@ impl<T: 'static> ClassEntity<T> {
634661
let parent:*mutzend_class_entry =self
635662
.parent
636663
.as_ref()
637-
.map(|parent|parent())
664+
.map(|parent| parent.as_class_entry())
638665
.map(|entry| entry.as_ptr()as*mut_)
639666
.unwrap_or(null_mut());
640667

@@ -800,20 +827,24 @@ impl InterfaceEntity {
800827
/// Register interface to `extends` the interfaces, due to the interface can
801828
/// extends multi interface, so this method can be called multi time.
802829
///
803-
/// *Because in the `MINIT` phase, the class starts to register,so the*
830+
/// *Because in the `MINIT` phase, the class starts to register,a*
804831
/// *closure is used to return the `ClassEntry` to delay the acquisition of*
805832
/// *the class.*
806833
///
807834
/// # Examples
808835
///
809836
/// ```no_run
810-
/// use phper::classes::{ClassEntry, InterfaceEntity};
837+
/// use phper::classes::{Interface, InterfaceEntity};
811838
///
812839
/// let mut interface = InterfaceEntity::new("MyInterface");
813-
/// interface.extends(|| ClassEntry::from_globals("Stringable").unwrap());
840+
/// interface.extends(Interface::from_name("Stringable"));
814841
/// ```
815-
pubfnextends(&mutself,interface:implFn() ->&'staticClassEntry +'static){
816-
self.extends.push(Box::new(interface));
842+
pubfnextends(&mutself,interface:Interface){
843+
self.extends.push(Box::new(move ||{
844+
let entry:&'staticClassEntry =
845+
unsafe{ std::mem::transmute(interface.as_class_entry())};
846+
entry
847+
}));
817848
}
818849

819850
#[allow(clippy::useless_conversion)]

‎tests/integration/src/classes.rs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,7 @@
1010

1111
use phper::{
1212
alloc::RefClone,
13-
classes::{
14-
ClassEntity,ClassEntry,Interface,InterfaceEntity,Visibility, array_access_class,
15-
iterator_class,
16-
},
13+
classes::{ClassEntity,ClassEntry,Interface,InterfaceEntity,StateClass,Visibility},
1714
functions::{Argument,ReturnType},
1815
modules::Module,
1916
types::{ArgumentTypeHint,ReturnTypeHint},
@@ -23,10 +20,11 @@ use std::{collections::HashMap, convert::Infallible};
2320

2421
pubfnintegrate(module:&mutModule){
2522
integrate_a(module);
26-
integrate_foo(module);
23+
let foo_class =integrate_foo(module);
2724
integrate_i_bar(module);
2825
integrate_static_props(module);
2926
integrate_i_constants(module);
27+
integrate_bar_extends_foo(module, foo_class);
3028
#[cfg(phper_major_version ="8")]
3129
integrate_stringable(module);
3230
}
@@ -78,7 +76,7 @@ struct Foo {
7876
array:HashMap<i64,ZVal>,
7977
}
8078

81-
fnintegrate_foo(module:&mutModule){
79+
fnintegrate_foo(module:&mutModule)->StateClass<Foo>{
8280
letmut class =ClassEntity::new_with_state_constructor("IntegrationTest\\Foo", ||Foo{
8381
position:0,
8482
array:Default::default(),
@@ -169,14 +167,14 @@ fn integrate_foo(module: &mut Module) {
169167
.argument(Argument::new("offset").with_type_hint(ArgumentTypeHint::Mixed))
170168
.return_type(ReturnType::new(ReturnTypeHint::Void));
171169

172-
module.add_class(class);
170+
module.add_class(class)
173171
}
174172

175173
fnintegrate_i_bar(module:&mutModule){
176174
letmut interface =InterfaceEntity::new(r"IntegrationTest\IBar");
177175

178-
interface.extends(||array_access_class());
179-
interface.extends(||iterator_class());
176+
interface.extends(Interface::from_name("ArrayAccess"));
177+
interface.extends(Interface::from_name("Iterator"));
180178

181179
interface
182180
.add_method("doSomethings")
@@ -224,6 +222,13 @@ fn integrate_static_props(module: &mut Module) {
224222
module.add_class(class);
225223
}
226224

225+
fnintegrate_bar_extends_foo(module:&mutModule,foo_class:StateClass<Foo>){
226+
letmut cls =ClassEntity::new(r"IntegrationTest\BarExtendsFoo");
227+
cls.extends(foo_class);
228+
cls.add_method("test",Visibility::Public, |_, _| phper::ok(()));
229+
module.add_class(cls);
230+
}
231+
227232
#[cfg(phper_major_version ="8")]
228233
fnintegrate_stringable(module:&mutModule){
229234
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 =newReflectionClass($bar);
107+
assert_true($reflection->isSubclassOf(IntegrationTest\Foo::class));

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp