> 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


Reply via email to