Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 30 additions & 7 deletions crates/macros/src/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,18 @@ pub struct StructAttributes {
modifier: Option<syn::Ident>,
/// An expression of `ClassFlags` to be applied to the class.
flags: Option<syn::Expr>,
extends: Option<syn::Expr>,
extends: Option<ClassEntryAttribute>,
#[darling(multiple)]
implements: Vec<syn::Expr>,
implements: Vec<ClassEntryAttribute>,
attrs: Vec<Attribute>,
}

#[derive(FromMeta, Debug)]
pub struct ClassEntryAttribute {
ce: syn::Expr,
stub: String,
}

pub fn parser(mut input: ItemStruct) -> Result<TokenStream> {
let attr = StructAttributes::from_attributes(&input.attrs)?;
let ident = &input.ident;
Expand Down Expand Up @@ -111,14 +117,13 @@ fn generate_registered_class_impl(
ident: &syn::Ident,
class_name: &str,
modifier: Option<&syn::Ident>,
extends: Option<&syn::Expr>,
implements: &[syn::Expr],
extends: Option<&ClassEntryAttribute>,
implements: &[ClassEntryAttribute],
fields: &[Property],
flags: Option<&syn::Expr>,
docs: &[String],
) -> TokenStream {
let modifier = modifier.option_tokens();
let extends = extends.option_tokens();

let fields = fields.iter().map(|prop| {
let name = prop.name();
Expand Down Expand Up @@ -149,16 +154,34 @@ fn generate_registered_class_impl(
#(#docs)*
};

let extends = if let Some(extends) = extends {
let ce = &extends.ce;
let stub = &extends.stub;
quote! {
Some((#ce, #stub))
}
} else {
quote! { None }
};

let implements = implements.iter().map(|imp| {
let ce = &imp.ce;
let stub = &imp.stub;
quote! {
(#ce, #stub)
}
});

quote! {
impl ::ext_php_rs::class::RegisteredClass for #ident {
const CLASS_NAME: &'static str = #class_name;
const BUILDER_MODIFIER: ::std::option::Option<
fn(::ext_php_rs::builders::ClassBuilder) -> ::ext_php_rs::builders::ClassBuilder
> = #modifier;
const EXTENDS: ::std::option::Option<
fn() -> &'static ::ext_php_rs::zend::ClassEntry
::ext_php_rs::class::ClassEntryInfo
> = #extends;
const IMPLEMENTS: &'static [fn() -> &'static ::ext_php_rs::zend::ClassEntry] = &[
const IMPLEMENTS: &'static [::ext_php_rs::class::ClassEntryInfo] = &[
#(#implements,)*
];
const FLAGS: ::ext_php_rs::flags::ClassFlags = #flags;
Expand Down
31 changes: 15 additions & 16 deletions crates/macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,19 @@ extern crate proc_macro;
///
/// ## Options
///
/// The attribute takes some options to modify the output of the class:
/// There are additional macros that modify the class. These macros **must** be
/// placed underneath the `#[php_class]` attribute.
///
/// - `name` - Changes the name of the class when exported to PHP. The Rust
/// struct name is kept the same. If no name is given, the name of the struct
/// is used. Useful for namespacing classes.
///
/// There are also additional macros that modify the class. These macros
/// **must** be placed underneath the `#[php_class]` attribute.
///
/// - `#[php(extends = ce)]` - Sets the parent class of the class. Can only be
/// used once. `ce` must be a function with the signature `fn() -> &'static
/// ClassEntry`.
/// - `#[php(implements = ce)]` - Implements the given interface on the class.
/// Can be used multiple times. `ce` must be a valid function with the
/// signature `fn() -> &'static ClassEntry`.
/// - `rename` - Changes the case of the class name when exported to PHP.
/// - `#[php(extends(ce = ce_fn, stub = "ParentClass"))]` - Sets the parent
/// class of the class. Can only be used once. `ce_fn` must be a function with
/// the signature `fn() -> &'static ClassEntry`.
/// - `#[php(implements(ce = ce_fn, stub = "InterfaceName"))]` - Implements the
/// given interface on the class. Can be used multiple times. `ce_fn` must be
/// a valid function with the signature `fn() -> &'static ClassEntry`.
///
/// You may also use the `#[php(prop)]` attribute on a struct field to use the
/// field as a PHP property. By default, the field will be accessible from PHP
Expand Down Expand Up @@ -122,8 +120,9 @@ extern crate proc_macro;
/// zend::ce
/// };
///
/// #[php_class(name = "Redis\\Exception\\RedisException")]
/// #[php(extends = ce::exception)]
/// #[php_class]
/// #[php(name = "Redis\\Exception\\RedisException")]
/// #[php(extends(ce = ce::exception, stub = "\\Exception"))]
/// #[derive(Default)]
/// pub struct RedisException;
///
Expand All @@ -144,8 +143,8 @@ extern crate proc_macro;
///
/// ## Implementing an Interface
///
/// To implement an interface, use `#[php(implements = ce)]` where `ce` is an
/// function returning a `ClassEntry`. The following example implements [`ArrayAccess`](https://www.php.net/manual/en/class.arrayaccess.php):
/// To implement an interface, use `#[php(implements(ce = ce_fn, stub =
/// "InterfaceName")]` where `ce_fn` is an function returning a `ClassEntry`. The following example implements [`ArrayAccess`](https://www.php.net/manual/en/class.arrayaccess.php):
///
/// ````rust,no_run,ignore
/// # #![cfg_attr(windows, feature(abi_vectorcall))]
Expand All @@ -158,7 +157,7 @@ extern crate proc_macro;
/// };
///
/// #[php_class]
/// #[php(implements = ce::arrayaccess)]
/// #[php(implements(ce = ce::arrayaccess, stub = "\\ArrayAccess"))]
/// #[derive(Default)]
/// pub struct EvenNumbersArray;
///
Expand Down
14 changes: 7 additions & 7 deletions guide/src/macros/classes.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ placed underneath the `#[php_class]` attribute.
name is kept the same. If no name is given, the name of the struct is used.
Useful for namespacing classes.
- `rename` - Changes the case of the class name when exported to PHP.
- `#[php(extends = ce)]` - Sets the parent class of the class. Can only be used once.
`ce` must be a function with the signature `fn() -> &'static ClassEntry`.
- `#[php(implements = ce)]` - Implements the given interface on the class. Can be used
multiple times. `ce` must be a valid function with the signature
- `#[php(extends(ce = ce_fn, stub = "ParentClass"))]` - Sets the parent class of the class. Can only be used once.
`ce_fn` must be a function with the signature `fn() -> &'static ClassEntry`.
- `#[php(implements(ce = ce_fn, stub = "InterfaceName"))]` - Implements the given interface on the class. Can be used
multiple times. `ce_fn` must be a valid function with the signature
`fn() -> &'static ClassEntry`.

You may also use the `#[php(prop)]` attribute on a struct field to use the field as a
Expand Down Expand Up @@ -97,7 +97,7 @@ use ext_php_rs::{

#[php_class]
#[php(name = "Redis\\Exception\\RedisException")]
#[php(extends = ce::exception)]
#[php(extends(ce = ce::exception, stub = "\\Exception"))]
#[derive(Default)]
pub struct RedisException;

Expand All @@ -118,7 +118,7 @@ pub fn get_module(module: ModuleBuilder) -> ModuleBuilder {

## Implementing an Interface

To implement an interface, use `#[php(implements = ce)]` where `ce` is an function returning a `ClassEntry`.
To implement an interface, use `#[php(implements(ce = ce_fn, stub = "InterfaceName")]` where `ce_fn` is an function returning a `ClassEntry`.
The following example implements [`ArrayAccess`](https://www.php.net/manual/en/class.arrayaccess.php):

````rust,no_run
Expand All @@ -132,7 +132,7 @@ use ext_php_rs::{
};

#[php_class]
#[php(implements = ce::arrayaccess)]
#[php(implements(ce = ce::arrayaccess, stub = "\\ArrayAccess"))]
#[derive(Default)]
pub struct EvenNumbersArray;

Expand Down
11 changes: 9 additions & 2 deletions guide/src/migration-guides/v0.14.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ pub fn get_module(module: ModuleBuilder) -> ModuleBuilder {
- `#[php(name = "NEW_NAME")]` - Renames the class
- `#[php(rename = case)]` - Changes the case of the class name
- `#[php(vis = "public")]` - Changes the visibility of the class
- `#[php(extends = "ParentClass")]` - Extends a parent class
- `#[php(implements = "Interface")]` - Implements an interface
- `#[php(extends(ce = ce_fn, stub = "ParentClass")]` - Extends a parent class
- `#[php(implements(ce = ce_fn, stub = "Interface"))]` - Implements an interface
- `#[php(prop)]` - Marks a field as a property

**Supported `#[php]` attributes (`impl`):**
Expand All @@ -116,6 +116,13 @@ pub fn get_module(module: ModuleBuilder) -> ModuleBuilder {

For elements in the `#[php_impl]` block see the respective function and constant attributes.

#### Extends and Implements

Extends and implements are now taking a second parameter which is the
`stub` name. This is the name of the class or interface in PHP.

This value is only used for stub generation and is not used for the class name in Rust.

### Constants

Mostly unchanged in terms of constant definition, however you now need to
Expand Down
Loading
Loading