Skip to content

Commit e0dad9f

Browse files
committed
simplify testcase
1 parent a897db0 commit e0dad9f

File tree

2 files changed

+67
-38
lines changed

2 files changed

+67
-38
lines changed

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

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

3939
## Extends & implements
4040

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
41+
To allow a class to extend another, you can use `ClassEntity.extends(StateClass<T>)`.
42+
A StateClass can either be obtained by registering your own class against the module, or
4343
by looking up the class by name (for example, for PHP built-in classes like `Exception`).
4444

4545
If you want class `Foo` extends `Bar`, and implements interface `Stringable`:
@@ -195,3 +195,51 @@ class MyHashMap {
195195

196196
}
197197
```
198+
199+
## Circular class dependencies
200+
If you wish to register classes which depend on each other, you can retrieve the bound class (`StateClass<T>`)
201+
from a `ClassEntity`, and use it in functions and methods:
202+
203+
```rust,no_run
204+
use phper::{
205+
classes::{ClassEntity, StateClass, Visibility},
206+
modules::Module,
207+
};
208+
209+
let mut module = Module::new(
210+
env!("CARGO_CRATE_NAME"),
211+
env!("CARGO_PKG_VERSION"),
212+
env!("CARGO_PKG_AUTHORS"),
213+
);
214+
215+
let mut a_cls = ClassEntity::new("A");
216+
let mut b_cls = ClassEntity::new("B");
217+
let a_bound_class = a_cls.bound_class();
218+
let b_bound_class = b_cls.bound_class();
219+
220+
a_cls.add_static_method("createB", Visibility::Public, move |_| {
221+
let object = b_bound_class.init_object()?;
222+
Ok::<_, phper::Error>(object)
223+
});
224+
b_cls.add_static_method("createA", Visibility::Public, move |_| {
225+
let object = a_bound_class.init_object()?;
226+
Ok::<_, phper::Error>(object)
227+
});
228+
229+
module.add_class(a_cls);
230+
module.add_class(b_cls);
231+
```
232+
233+
This is equivalent to the following PHP code:
234+
```php
235+
class A {
236+
public static function createB(): B {
237+
return new B();
238+
}
239+
}
240+
class B {
241+
public static function createA(): A {
242+
return new A();
243+
}
244+
}
245+
```

tests/integration/src/classes.rs

Lines changed: 17 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ use phper::{
1717
values::ZVal,
1818
};
1919
use std::{collections::HashMap, convert::Infallible};
20-
use std::rc::Rc;
2120

2221
pub fn integrate(module: &mut Module) {
2322
integrate_a(module);
@@ -238,46 +237,28 @@ fn integrate_dependent_classes(module: &mut Module) {
238237
let mut a_cls = ClassEntity::new(A_CLS);
239238
let mut b_cls = ClassEntity::new(B_CLS);
240239

241-
// Placeholder, will clone StateClass into closures after registration
242-
let a_cls_ref = std::rc::Rc::new(std::cell::RefCell::new(None));
243-
let b_cls_ref = std::rc::Rc::new(std::cell::RefCell::new(None));
244-
245-
{
246-
let b_cls_ref = Rc::clone(&b_cls_ref);
247-
a_cls.add_static_method("createB", Visibility::Public, move |_| {
248-
let borrow = b_cls_ref.borrow();
249-
let b_state: &StateClass<()> = borrow
250-
.as_ref()
251-
.expect("B class not registered");
252-
let obj = b_state.init_object()?;
253-
Ok::<_, phper::Error>(obj)
254-
})
255-
.return_type(ReturnType::new(ReturnTypeHint::ClassEntry(String::from(B_CLS))));
256-
}
257-
258-
{
259-
let a_cls_ref = Rc::clone(&a_cls_ref);
260-
b_cls.add_static_method("createA", Visibility::Public, move |_| {
261-
let borrow = a_cls_ref.borrow();
262-
let a_state: &StateClass<()> = borrow
263-
.as_ref()
264-
.expect("A class not registered");
265-
let obj = a_state.init_object()?;
266-
Ok::<_, phper::Error>(obj)
267-
})
268-
.return_type(ReturnType::new(ReturnTypeHint::ClassEntry(String::from(A_CLS))));
269-
}
240+
let a_bound_class = a_cls.bound_class();
241+
let b_bound_class = b_cls.bound_class();
270242

243+
a_cls
244+
.add_static_method("createB", Visibility::Public, move |_| {
245+
let object = b_bound_class.init_object()?;
246+
Ok::<_, phper::Error>(object)
247+
})
248+
.return_type(ReturnType::new(ReturnTypeHint::ClassEntry(B_CLS.into())));
271249

272-
// Register both classes and save the StateClass into shared RefCells
273-
let a_state = module.add_class(a_cls);
274-
let b_state = module.add_class(b_cls);
250+
b_cls
251+
.add_static_method("createA", Visibility::Public, move |_| {
252+
let object = a_bound_class.init_object()?;
253+
Ok::<_, phper::Error>(object)
254+
})
255+
.return_type(ReturnType::new(ReturnTypeHint::ClassEntry(A_CLS.into())));
275256

276-
*a_cls_ref.borrow_mut() = Some(a_state);
277-
*b_cls_ref.borrow_mut() = Some(b_state);
257+
// Register both classes
258+
module.add_class(a_cls);
259+
module.add_class(b_cls);
278260
}
279261

280-
281262
#[cfg(phper_major_version = "8")]
282263
fn integrate_stringable(module: &mut Module) {
283264
use phper::{functions::ReturnType, types::ReturnTypeHint};

0 commit comments

Comments
 (0)