Skip to content

Commit 53bd7a1

Browse files
authored
feat: Enhance enum functionality with access methods (#203)
1 parent 60a1053 commit 53bd7a1

File tree

6 files changed

+612
-23
lines changed

6 files changed

+612
-23
lines changed

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

Lines changed: 188 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -225,18 +225,171 @@ $colorFromValue = Color::from("FF0000"); // Returns RED
225225
$colorOrNull = Color::tryFrom("INVALID"); // Returns null (when the value doesn't exist)
226226
```
227227

228+
## Using EnumCase for Direct Access
229+
230+
When you call `add_case()` on an enum entity, it returns an `EnumCase` instance that you can use for direct access to that case later. This is more efficient than looking up the enum case by name each time you need it.
231+
232+
Here's an example showing how to use EnumCase within static methods of the enum:
233+
234+
```rust,no_run
235+
use phper::{
236+
modules::Module,
237+
php_get_module,
238+
enums::EnumEntity,
239+
classes::Visibility,
240+
alloc::ToRefOwned,
241+
};
242+
243+
#[php_get_module]
244+
pub fn get_module() -> Module {
245+
let mut module = Module::new(
246+
env!("CARGO_CRATE_NAME"),
247+
env!("CARGO_PKG_VERSION"),
248+
env!("CARGO_PKG_AUTHORS"),
249+
);
250+
251+
// Create a pure enum
252+
let mut pure_enum_entity = EnumEntity::new("PureEnum");
253+
254+
// Store references to enum cases when adding them
255+
let one_case = pure_enum_entity.add_case("ONE", ());
256+
let _two_case = pure_enum_entity.add_case("TWO", ());
257+
258+
// Add static method that returns the ONE case
259+
pure_enum_entity.add_static_method("getOneCase", Visibility::Public, {
260+
// Clone the EnumCase because it will be moved into the closure
261+
move |_| {
262+
// Get the case object directly from EnumCase
263+
let one_obj = one_case.clone().get_mut_case();
264+
let result = one_obj.to_ref_owned();
265+
phper::ok(result)
266+
}
267+
});
268+
269+
// Register the enum to the module
270+
module.add_enum(pure_enum_entity);
271+
272+
// Create an int-backed enum
273+
let mut int_enum_entity = EnumEntity::<i64>::new("IntEnum");
274+
275+
// Store reference to LOW case
276+
let low_case = int_enum_entity.add_case("LOW", 10);
277+
let _high_case = int_enum_entity.add_case("HIGH", 100);
278+
279+
// Add static method that returns the LOW case
280+
int_enum_entity.add_static_method("getLowCase", Visibility::Public, {
281+
move |_| {
282+
let low_obj = low_case.clone().get_mut_case();
283+
let result = low_obj.to_ref_owned();
284+
phper::ok(result)
285+
}
286+
});
287+
288+
// Register the enum to the module
289+
module.add_enum(int_enum_entity);
290+
291+
module
292+
}
293+
```
294+
295+
This creates PHP enums with static methods that can access specific cases:
296+
297+
```php
298+
enum PureEnum {
299+
case ONE;
300+
case TWO;
301+
302+
public static function getOneCase(): self {
303+
return self::ONE;
304+
}
305+
}
306+
307+
enum IntEnum: int {
308+
case LOW = 10;
309+
case HIGH = 100;
310+
311+
public static function getLowCase(): self {
312+
return self::LOW;
313+
}
314+
}
315+
```
316+
317+
## Using Enum::from_name
318+
319+
If you don't have direct access to the EnumCase, you can use `Enum::from_name()` to get an enum by its name, and then use `get_case()` or `get_mut_case()` to access specific cases:
320+
321+
```rust,no_run
322+
use phper::{
323+
enums::Enum,
324+
enums::EnumEntity,
325+
classes::Visibility,
326+
alloc::ToRefOwned,
327+
};
328+
329+
fn create_enum_with_dynamic_lookup() -> EnumEntity {
330+
let mut enum_entity = EnumEntity::new("DynamicEnum");
331+
enum_entity.add_case("ONE", ());
332+
enum_entity.add_case("TWO", ());
333+
334+
// Add a static method that looks up cases dynamically
335+
enum_entity.add_static_method("getCaseByName", Visibility::Public, |args| {
336+
// Get case name from parameters
337+
let case_name = args[0].expect_z_str()?.to_string_lossy();
338+
339+
// Use Enum::from_name to get the enum
340+
let mut enum_obj = Enum::from_name("DynamicEnum");
341+
342+
// Try to get the requested case
343+
let case = unsafe { enum_obj.get_mut_case(&case_name)? };
344+
let result = case.to_ref_owned();
345+
346+
phper::ok(result)
347+
});
348+
349+
enum_entity
350+
}
351+
```
352+
353+
> **Important**: The `get_case()` and `get_mut_case()` methods on `Enum` are marked as unsafe because they can cause segmentation faults if the case doesn't exist.
354+
355+
## Bound Enum
356+
357+
You can use the `bound_enum()` method to get a reference to the enum that can be used in methods or functions:
358+
359+
```rust,no_run
360+
use phper::{enums::EnumEntity, classes::Visibility, alloc::ToRefOwned};
361+
362+
pub fn make_status_enum() -> EnumEntity {
363+
let mut enum_entity = EnumEntity::new("Status");
364+
enum_entity.add_case("Active", ());
365+
enum_entity.add_case("Inactive", ());
366+
367+
// Get a reference to the enum that will be created
368+
let status_enum = enum_entity.bound_enum();
369+
370+
// Add a static method that uses the bound enum
371+
enum_entity.add_static_method("getActiveCase", Visibility::Public, move |_| {
372+
// Use the bound enum to get the Active case
373+
let active_case = unsafe { status_enum.clone().get_mut_case("Active")? };
374+
phper::ok(active_case.to_ref_owned())
375+
});
376+
377+
enum_entity
378+
}
379+
```
380+
228381
## Complete Example
229382

230-
Here's a comprehensive example using both pure and backed enums:
383+
Here's a comprehensive example using both pure and backed enums with static methods:
231384

232385
```rust,no_run
233386
use phper::{
234387
modules::Module,
235388
php_get_module,
236389
enums::EnumEntity,
237-
classes::Visibility
390+
classes::Visibility,
391+
alloc::ToRefOwned,
238392
};
239-
use std::convert::Infallible;
240393
241394
#[php_get_module]
242395
pub fn get_module() -> Module {
@@ -248,19 +401,44 @@ pub fn get_module() -> Module {
248401
249402
// Pure enum
250403
let mut status = EnumEntity::new("Status");
251-
status.add_case("PENDING", ());
252-
status.add_case("ACTIVE", ());
253-
status.add_case("INACTIVE", ());
404+
let pending_case = status.add_case("PENDING", ());
405+
let active_case = status.add_case("ACTIVE", ());
406+
let inactive_case = status.add_case("INACTIVE", ());
407+
408+
// Add constants
254409
status.add_constant("VERSION", "1.0.0");
410+
411+
// Add static method that returns the active state
412+
status.add_static_method("getActiveStatus", Visibility::Public, {
413+
move |_| {
414+
let obj = active_case.clone().get_mut_case();
415+
phper::ok(obj.to_ref_owned())
416+
}
417+
});
418+
419+
// Add static method that returns status description
255420
status.add_static_method("getDescription", Visibility::Public, |_| {
256-
Ok::<_, Infallible>("Status enumeration")
421+
phper::ok("Status enumeration")
257422
});
258423
259424
// Integer-backed enum
260425
let mut level = EnumEntity::<i64>::new("Level");
261-
level.add_case("LOW", 1);
262-
level.add_case("MEDIUM", 5);
263-
level.add_case("HIGH", 10);
426+
let low_case = level.add_case("LOW", 1);
427+
let medium_case = level.add_case("MEDIUM", 5);
428+
let high_case = level.add_case("HIGH", 10);
429+
430+
// Add static method that returns level by value
431+
level.add_static_method("getLevelByValue", Visibility::Public, {
432+
move |args| {
433+
let value: i64 = args[0].expect_long()?;
434+
let case_obj = match value {
435+
v if v < 3 => low_case.clone().get_mut_case(),
436+
v if v < 8 => medium_case.clone().get_mut_case(),
437+
_ => high_case.clone().get_mut_case(),
438+
};
439+
phper::ok(case_obj.to_ref_owned())
440+
}
441+
});
264442
265443
// Register enums to the module
266444
module.add_enum(status);

0 commit comments

Comments
 (0)