> On Jun 19, 2024, at 8:33 AM, Erick de Azevedo Lima <ericklima.c...@gmail.com > <mailto:ericklima.c...@gmail.com>> wrote: > > Hello everybody. > > I found myself wanting this feature (that I first encountered when > programming in C#) for removing a workaround from a codebase I work from time > to time. > I searched internals and found a discussion from almost a decade ago. That > discussion did not end well, mostly because of insulting accusations. > I then decided to do some research on this subject and found out that it's a > pretty common feature in other OOP languages. > Also, as I started studying the php-src (and missed the days when I used to > program in C in my main job), I decided to do an implementation myself even > before presenting the RFC. > The implementation link can also be found at the RFC. > > You can read the RFC here: > https://wiki.php.net/rfc/static_constructor > <https://wiki.php.net/rfc/static_constructor> > > Regards, > > Erick
1. I noticed you did not include an example for Go so I wrote one up for you in a Go playground. Hopefully you can include Go's approach in your RFC? > https://goplay.tools/snippet/6lvAQdye9P9 > <https://goplay.tools/snippet/6lvAQdye9P9> 2. Also, in the past I made frequent use of "on_load()" methods that I would call immediately after the class code. I always wanted a static initializer — and even discussed it with Ben Ramsay at an after-event for Atlanta PHP meetup years ago — but I never proposed in as an RFC and cannot remember if I ever discussed here on the list. Even though I no longer actively use or maintain the following library I wanted to provide you with links for each of the different use-case where I had an `on_load()` method and would have used a static initializer had it been available in hopes they may inspire you to enhance your RFC with new use-cases. I am also sharing for others to see the different use-cases: - https://github.com/wplib/wplib/blob/master/wplib.php#L142 <https://github.com/wplib/wplib/blob/master/wplib.php#L142> - https://github.com/wplib/wplib/blob/master/modules/posts/posts.php#L43 <https://github.com/wplib/wplib/blob/master/modules/posts/posts.php#L43> - https://github.com/wplib/wplib/blob/master/modules/theme/theme.php#L14 <https://github.com/wplib/wplib/blob/master/modules/theme/theme.php#L14> - https://github.com/wplib/wplib/blob/master/modules/role-administrator/role-administrator.php#L35 <https://github.com/wplib/wplib/blob/master/modules/role-administrator/role-administrator.php#L35> - https://github.com/wplib/wplib/blob/master/modules/roles/includes/class-role-module-base.php#L33 <https://github.com/wplib/wplib/blob/master/modules/roles/includes/class-role-module-base.php#L33> - https://github.com/wplib/wplib/blob/master/modules/commit-reviser/commit-reviser.php#L13 <https://github.com/wplib/wplib/blob/master/modules/commit-reviser/commit-reviser.php#L13> - https://github.com/wplib/wplib/blob/master/modules/helpers-html/helpers-html.php#L16 <https://github.com/wplib/wplib/blob/master/modules/helpers-html/helpers-html.php#L16> 3. One thing about "best practices" for static initializers. When using a package-level variable in Go initializations and for those PHP static classes with `on_load()` methods I found it problematic to add anything that could fail in a reasonable use-case, and I would recommend that this would become the advice given as a best practice for using static initializers. In my PHP examples above I do happen to assume the database is open and exists but only because the library is for use with WordPress as a must-load plugin, and if the database is not available my plugin will never get loaded. In Go I never use database access code or remote API calls, or anything that could generate an error. I instead create "initialize" methods and call them explicitly in `main()` or some other func that `main()` calls. In PHP you can have a syntax error at runtime, but in that case it will error as soon as you try to autoload the PHP file so I do not think syntax errors should be real concern here, only runtime errors. 4. To elaborate more about "best practices" where I see static initializers being especially valuable it when you want to initialize immutable data, and especially when that data is in complex form such as an object vs. just a simple value. Here is one such example of this which initializes the default labels for a WordPress post-type: https://github.com/wplib/wplib/blob/master/modules/posts/posts.php#L54-L64 <https://github.com/wplib/wplib/blob/master/modules/posts/posts.php#L54-L64> 5. Another use-case is registering "hooks" defined by a framework, such as the `wp_loaded` hook in WordPress: https://github.com/wplib/wplib/blob/master/modules/posts/posts.php#L68C28-L68C37 <https://github.com/wplib/wplib/blob/master/modules/posts/posts.php#L68C28-L68C37> 6. Yes another use-case would be to make a framework more robust and to provide guidance to a user for what they are doing wrong. Here I am actually throwing an error when the it is clear the classes are being initialized out-of-order: https://github.com/wplib/wplib/blob/master/wplib.php#L157 <https://github.com/wplib/wplib/blob/master/wplib.php#L157> 7. Still another is loading related .PHP files that are required so as not to have to rely on the autoloader. https://github.com/wplib/wplib/blob/master/wplib.php#L167 <https://github.com/wplib/wplib/blob/master/wplib.php#L167>. Here I would also suggest guidance about not including any code that can fail at load time during the normal course of execution meaning syntax errors are okay but the loaded code should really never generate a runtime errors. 8. A big use-case too is allowing static classes to register themselves as being able to provide a service to another class defined by the application or framework. This allows a class to self-describe its behavior and capabilities such as how my library allows the registration of the class as a "Helper" for the main class and how it allows registering a class as representing a "Role" in the framework: https://github.com/wplib/wplib/blob/master/modules/posts/posts.php#L48 <https://github.com/wplib/wplib/blob/master/modules/posts/posts.php#L48> https://github.com/wplib/wplib/blob/master/modules/role-administrator/role-administrator.php#L37 <https://github.com/wplib/wplib/blob/master/modules/role-administrator/role-administrator.php#L37> This is much like how a pub-sub system allows others to subscribe to the publisher and the publisher does not need to know in advance all the subscribers to the system. 9. Regarding Larry's concern for test mocking, if the only things that static initialize functions are doing is initializing immutable data, registering hooks, pre-loading non-error generating .PHP files, and/or registering classes for special use-cases then there is #fyi (little or?) no need to mock them for testing purposes. For developers following said guidance I do not see static initializers as creating a challenge for testing. -Mike P.S. I think it would be great if static initializers threw a runtime error if they attempted to do anything that could throw an error — at least not without a try-catch to absorb the error — but as I cannot envision how that would be possible and still be acceptably performant I think the only approach should be provide the community with guidance on how and how not to use static initializers. #fwiw