@@ -51,12 +51,16 @@ extern crate proc_macro;
5151/// publicly with the same name as the field. Property types must implement
5252/// `IntoZval` and `FromZval`.
5353///
54- /// You can rename the property with options:
54+ /// You can customize properties with these options:
5555///
56- /// - `name` - Allows you to rename the property, e.g. `#[php(name =
56+ /// - `name` - Allows you to rename the property, e.g. `#[php(prop, name =
5757/// "new_name")]`
5858/// - `change_case` - Allows you to rename the property using rename rules, e.g.
59- /// `#[php(change_case = PascalCase)]`
59+ /// `#[php(prop, change_case = PascalCase)]`
60+ /// - `static` - Makes the property static (shared across all instances), e.g.
61+ /// `#[php(prop, static)]`
62+ /// - `flags` - Sets property visibility flags, e.g. `#[php(prop, flags =
63+ /// ext_php_rs::flags::PropertyFlags::Private)]`
6064///
6165/// ## Restrictions
6266///
@@ -204,6 +208,72 @@ extern crate proc_macro;
204208/// }
205209/// # fn main() {}
206210/// ````
211+ ///
212+ /// ## Static Properties
213+ ///
214+ /// Static properties are shared across all instances of a class. Use
215+ /// `#[php(prop, static)]` to declare a static property. Unlike instance
216+ /// properties, static properties are managed entirely by PHP and do not use
217+ /// Rust property handlers.
218+ ///
219+ /// You can specify a default value using the `default` attribute:
220+ ///
221+ /// ```rust,no_run,ignore
222+ /// # #![cfg_attr(windows, feature(abi_vectorcall))]
223+ /// # extern crate ext_php_rs;
224+ /// use ext_php_rs::prelude::*;
225+ /// use ext_php_rs::class::RegisteredClass;
226+ ///
227+ /// #[php_class]
228+ /// pub struct Counter {
229+ /// #[php(prop)]
230+ /// pub instance_value: i32,
231+ /// #[php(prop, static, default = 0)]
232+ /// pub count: i32,
233+ /// #[php(prop, static, flags = ext_php_rs::flags::PropertyFlags::Private)]
234+ /// pub internal_state: String,
235+ /// }
236+ ///
237+ /// #[php_impl]
238+ /// impl Counter {
239+ /// pub fn __construct(value: i32) -> Self {
240+ /// Self {
241+ /// instance_value: value,
242+ /// count: 0,
243+ /// internal_state: String::new(),
244+ /// }
245+ /// }
246+ ///
247+ /// /// Increment the static counter from Rust
248+ /// pub fn increment() {
249+ /// let ce = Self::get_metadata().ce();
250+ /// let current: i64 = ce.get_static_property("count").unwrap_or(0);
251+ /// ce.set_static_property("count", current + 1).unwrap();
252+ /// }
253+ ///
254+ /// /// Get the current count
255+ /// pub fn get_count() -> i64 {
256+ /// let ce = Self::get_metadata().ce();
257+ /// ce.get_static_property("count").unwrap_or(0)
258+ /// }
259+ /// }
260+ ///
261+ /// #[php_module]
262+ /// pub fn get_module(module: ModuleBuilder) -> ModuleBuilder {
263+ /// module.class::<Counter>()
264+ /// }
265+ /// # fn main() {}
266+ /// ```
267+ ///
268+ /// From PHP, you can access static properties directly on the class:
269+ ///
270+ /// ```php
271+ /// // No need to initialize - count already has default value of 0
272+ /// Counter::increment();
273+ /// Counter::increment();
274+ /// echo Counter::$count; // 2
275+ /// echo Counter::getCount(); // 2
276+ /// ```
207277// END DOCS FROM classes.md
208278#[ proc_macro_attribute]
209279pub fn php_class ( args : TokenStream , input : TokenStream ) -> TokenStream {
@@ -812,6 +882,34 @@ fn php_module_internal(args: TokenStream2, input: TokenStream2) -> TokenStream2
812882/// The `#[php(defaults)]` and `#[php(optional)]` attributes operate the same as
813883/// the equivalent function attribute parameters.
814884///
885+ /// ### Static Methods
886+ ///
887+ /// Methods that do not take a `&self` or `&mut self` parameter are
888+ /// automatically exported as static methods. These can be called on the class
889+ /// itself without creating an instance.
890+ ///
891+ /// ```rust,ignore
892+ /// #[php_impl]
893+ /// impl MyClass {
894+ /// // Static method - no self parameter
895+ /// pub fn create_default() -> Self {
896+ /// Self { /* ... */ }
897+ /// }
898+ ///
899+ /// // Instance method - takes &self
900+ /// pub fn get_value(&self) -> i32 {
901+ /// self.value
902+ /// }
903+ /// }
904+ /// ```
905+ ///
906+ /// From PHP:
907+ ///
908+ /// ```php
909+ /// $obj = MyClass::createDefault(); // Static call
910+ /// $val = $obj->getValue(); // Instance call
911+ /// ```
912+ ///
815913/// ### Constructors
816914///
817915/// By default, if a class does not have a constructor, it is not constructable
0 commit comments