Skip to content

Commit e360e76

Browse files
committed
feat: Add constructor visability
Add visability in constructor meta, and feature mark constructor as private and protected
1 parent 6869625 commit e360e76

File tree

8 files changed

+81
-21
lines changed

8 files changed

+81
-21
lines changed

crates/macros/src/function.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,11 @@ impl<'a> Function<'a> {
308308

309309
/// Returns a constructor metadata object for this function. This doesn't
310310
/// check if the function is a constructor, however.
311-
pub fn constructor_meta(&self, class: &syn::Path) -> TokenStream {
311+
pub fn constructor_meta(
312+
&self,
313+
class: &syn::Path,
314+
visibility: Option<&Visibility>,
315+
) -> TokenStream {
312316
let ident = self.ident;
313317
let (required, not_required) = self.args.split_args(self.optional.as_ref());
314318
let required_args = required
@@ -339,6 +343,7 @@ impl<'a> Function<'a> {
339343
}
340344
});
341345
let docs = &self.docs;
346+
let flags = visibility.option_tokens();
342347

343348
quote! {
344349
::ext_php_rs::class::ConstructorMeta {
@@ -368,7 +373,8 @@ impl<'a> Function<'a> {
368373
#variadic
369374
}
370375
inner
371-
}
376+
},
377+
flags: #flags
372378
}
373379
}
374380
}

crates/macros/src/impl_.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ struct ParsedImpl<'a> {
120120
change_method_case: RenameRule,
121121
change_constant_case: RenameRule,
122122
functions: Vec<FnBuilder>,
123-
constructor: Option<Function<'a>>,
123+
constructor: Option<(Function<'a>, Option<Visibility>)>,
124124
constants: Vec<Constant<'a>>,
125125
}
126126

@@ -212,7 +212,7 @@ impl<'a> ParsedImpl<'a> {
212212
let mut modifiers: HashSet<MethodModifier> = HashSet::new();
213213

214214
if matches!(opts.ty, MethodTy::Constructor) {
215-
if self.constructor.replace(func).is_some() {
215+
if self.constructor.replace((func, opts.vis.into())).is_some() {
216216
bail!(method => "Only one constructor can be provided per class.");
217217
}
218218
} else {
@@ -264,7 +264,7 @@ impl<'a> ParsedImpl<'a> {
264264
let constructor = self
265265
.constructor
266266
.as_ref()
267-
.map(|func| func.constructor_meta(self.path))
267+
.map(|(func, vis)| func.constructor_meta(self.path, vis.as_ref()))
268268
.option_tokens();
269269
let constants = self.constants.iter().map(|c| {
270270
let name = &c.name;
@@ -306,11 +306,8 @@ impl quote::ToTokens for FnBuilder {
306306
let builder = &self.builder;
307307
// TODO(cole_d): allow more flags via attributes
308308
let mut flags = vec![];
309-
flags.push(match self.vis {
310-
Visibility::Public => quote! { ::ext_php_rs::flags::MethodFlags::Public },
311-
Visibility::Protected => quote! { ::ext_php_rs::flags::MethodFlags::Protected },
312-
Visibility::Private => quote! { ::ext_php_rs::flags::MethodFlags::Private },
313-
});
309+
let vis = &self.vis;
310+
flags.push(quote! { #vis });
314311
for flag in &self.modifiers {
315312
flags.push(quote! { #flag });
316313
}

crates/macros/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -712,7 +712,7 @@ fn php_module_internal(args: TokenStream2, input: TokenStream2) -> TokenStream2
712712
/// - `#[php(optional = i)]` - Sets the first optional parameter. Note that this
713713
/// also sets the remaining parameters as optional, so all optional parameters
714714
/// must be a variant of `Option<T>`.
715-
/// - `#[php(public)]`, `#[php(protected)]` and `#[php(private)]` - Sets the
715+
/// - `#[php(vis = "public")]`, `#[php(vis = "protected")]` and `#[php(vis = "private")]` - Sets the
716716
/// visibility of the method.
717717
/// - `#[php(name = "method_name")]` - Renames the PHP method to a different
718718
/// identifier, without renaming the Rust method name.

crates/macros/src/parsing.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use convert_case::{Case, Casing};
22
use darling::FromMeta;
3+
use quote::{quote, ToTokens};
34

45
const MAGIC_METHOD: [&str; 17] = [
56
"__construct",
@@ -31,6 +32,17 @@ pub enum Visibility {
3132
Protected,
3233
}
3334

35+
impl ToTokens for Visibility {
36+
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
37+
match self {
38+
Visibility::Public => quote! { ::ext_php_rs::flags::MethodFlags::Public },
39+
Visibility::Protected => quote! { ::ext_php_rs::flags::MethodFlags::Protected },
40+
Visibility::Private => quote! { ::ext_php_rs::flags::MethodFlags::Private },
41+
}
42+
.to_tokens(tokens);
43+
}
44+
}
45+
3446
pub trait Rename {
3547
fn rename(&self, rule: RenameRule) -> String;
3648
}

src/builders/class.rs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -238,16 +238,18 @@ impl ClassBuilder {
238238
"Class name in builder does not match class name in `impl RegisteredClass`."
239239
);
240240
self.object_override = Some(create_object::<T>);
241-
self.method(
242-
{
243-
let mut func = FunctionBuilder::new("__construct", constructor::<T>);
244-
if let Some(ConstructorMeta { build_fn, .. }) = T::constructor() {
245-
func = build_fn(func);
246-
}
247-
func
248-
},
249-
MethodFlags::Public,
250-
)
241+
242+
let mut func = FunctionBuilder::new("__construct", constructor::<T>);
243+
let mut Visibility = MethodFlags::Public;
244+
if let Some(ConstructorMeta {
245+
build_fn, flags, ..
246+
}) = T::constructor()
247+
{
248+
func = build_fn(func);
249+
Visibility = flags.unwrap_or(MethodFlags::Public);
250+
}
251+
252+
self.method(func, Visibility)
251253
}
252254

253255
/// Function to register the class with PHP. This function is called after

src/class.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ pub struct ConstructorMeta<T> {
8282
/// Function called to build the constructor function. Usually adds
8383
/// arguments.
8484
pub build_fn: fn(FunctionBuilder) -> FunctionBuilder,
85+
/// Add constructor modification
86+
pub flags: Option<MethodFlags>,
8587
}
8688

8789
/// Result returned from a constructor of a class.

tests/src/integration/class/class.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,11 @@
4343
assert_exception_thrown(fn() => $arrayAccess['foo']);
4444
assert($arrayAccess[0] === true);
4545
assert($arrayAccess[1] === false);
46+
47+
$classReflection = new ReflectionClass(TestClassMethodVisibility::class);
48+
assert($classReflection->getMethod('__construct')->isPrivate());
49+
assert($classReflection->getMethod('private')->isPrivate());
50+
assert($classReflection->getMethod('protected')->isProtected());
51+
52+
$classReflection = new ReflectionClass(TestClassProtectedConstruct::class);
53+
assert($classReflection->getMethod('__construct')->isProtected());

tests/src/integration/class/mod.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,12 +144,45 @@ impl TestClassExtendsImpl {
144144
}
145145
}
146146

147+
#[php_class]
148+
struct TestClassMethodVisibility;
149+
150+
#[php_impl]
151+
impl TestClassMethodVisibility {
152+
#[php(vis = "private")]
153+
fn __construct() -> Self {
154+
Self
155+
}
156+
157+
#[php(vis = "private")]
158+
fn private() -> u32 {
159+
3
160+
}
161+
162+
#[php(vis = "protected")]
163+
fn protected() -> u32 {
164+
3
165+
}
166+
}
167+
#[php_class]
168+
struct TestClassProtectedConstruct;
169+
170+
#[php_impl]
171+
impl TestClassProtectedConstruct {
172+
#[php(vis = "protected")]
173+
fn __construct() -> Self {
174+
Self
175+
}
176+
}
177+
147178
pub fn build_module(builder: ModuleBuilder) -> ModuleBuilder {
148179
builder
149180
.class::<TestClass>()
150181
.class::<TestClassArrayAccess>()
151182
.class::<TestClassExtends>()
152183
.class::<TestClassExtendsImpl>()
184+
.class::<TestClassMethodVisibility>()
185+
.class::<TestClassProtectedConstruct>()
153186
.function(wrap_function!(test_class))
154187
.function(wrap_function!(throw_exception))
155188
}

0 commit comments

Comments
 (0)