Hi all.

Answering to Larry:
> More complex initialization of things like lookup tables or "dynamic
constants" (like if you wanted to record "now" to use for later
comparisons).
Those are my use cases, to be honest.

> For that reason, therefore, I don't like the current approach, especially
for this line: "Programmers have the option to call the __staticConstruct
method to reset static properties values if desired."
I just laughed at myself when I read this. As I said, my main inspiration
was the C# implementation and there, the static constructor can only be
called by the engine.
And that was my intention, but then I remembered that the "__construct"
method can be called on an already constructed object and I implemented it
this way.
If it's a consensus to remove it, I'll gladly do it. :-)

> Your examples would be clearer if you leveraged the ??= operator, which
would reduce your initializeMinDate() methods to a single line.
Yes, it's true. As a former teaching assistant, I tend to give examples
that might be longer than necessary, with the intention of being as clear
as possible.
In this case, it was to emphasize the fact that we must implement a logic
to check (the "if" at the beginning of the method) if the property was
already initialized.

> What I object to is holding up Java as being "stricter about OO
principles."  OO principles are not a uniform, monolithic thing.
> In fact, the person who invented the term Object-Oriented has said before
that C++ and Java are *not* what he had in mind.
> "Class based programming" is not what OOP was intended to be.
To be honest, when I wrote this part, I was indeed thinking about "class
based" programming.
And Java is stricter than PHP and C++ in this sense: It does not have loose
functions, everything must be inside a class.
And even though "Class based programming" is not what OOP was intended to
be, it's what's mostly found out there: OOP = Class based programming
But my main point here is to show that this feature is often provided
because it's proven to be useful for programmers of multiple programming
languages.

Answering to Mike:

> 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?
No, I'm not familiar enough with Go to provide examples, so I did not
consider it. As you provided the example, I'll gladly include it. Thank you!

> 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.
Yes, I think that's "the" use case.

Tim:

> I would suggest `__constructStatic()`. This matches the existing naming
> pattern of `__callStatic()` being the companion to `__call()`.
Noted. I'm not really attached to any name and your point makes a lot of
sense.

Ilija:

> I see that you're using zend_class_init_statics() as a hook to call
__static_construct().
Yes, I thought that lazy initialization would cover most of the use-cases
for initializing static variables, so that seemed the best place to do it.

> This makes the initialization order
> unpredictable, because static properties are initialized lazily when
> the class is first used (when instantiated, when accessing constants,
etc.).
>From my tests, the static variables initialization is even lazier: The
"zend_class_init_statics" is only called when you try to access a static
variable.
See this example:

class C1
{
    private static \DateTimeInterface $v1;

    public function __construct()
    {
        echo __METHOD__ . PHP_EOL;
    }

    private static function __staticConstruct()
    {
        self::$v1 = new \DateTimeImmutable('2024-06-19 00:00:00');
        echo 'calling ' . __METHOD__ . PHP_EOL;
        echo C2::USING_SYMBOL_DECLARED_LATER . PHP_EOL;
    }

    public static function getV1()
    {
        echo 'Before accessing C1::$v1 variable' . PHP_EOL;

        return self::$v1;
    }
}

class C2
{
    public const USING_SYMBOL_DECLARED_LATER =
'C2::USING_SYMBOL_DECLARED_LATER';
}

$obj1 = new C1(); //should not trigger zend_class_init_statics()

echo C1::getV1()->format('Y-m-d') . PHP_EOL; //

This example prints:





*C1::__constructBefore accessing C1::$v1 variablecalling
C1::__staticConstructC2::USING_SYMBOL_DECLARED_LATER2024-06-19*

> Lazy evaluation might be ok if order is clearly defined. Making the
> order undefined makes it hard (or impossible) to understand which
> symbols declared in the current file may be used from __static_construct()
Can you provide an example for that? I'm not sure if I understood
everything correctly.

> ... is further complicated by early-binding. I'm not sure what the best
approach is here.
One of my first thoughts was to perform this at the end of class linking
(on function *zend_do_link_class*()),
but then I came to a conclusion that performing it during the already
existing lazy init would cover most use cases.

Mike again:

> Consider that some uses for a static function need to always occur no
matter
> whether or not any other method of the class is called. My previous email
[1] covered several.
> Here [2] is a discussion on StackOverflow of "hooks" that should be
eagerly loaded.
Yes, I considered this approach before. But then I realized that for
covering the properties initialization,
this already existing lazy loading mechanism would suffice. At the end of
the RFC,
I consider future scope to create an early-init. In my opinion, as it
covers a more general use for this init,
it should be implemented maybe using another magic method, like "__load" or
"__link",
which would be hooks on class loading process and not specific to static
variables initialization

Lynn:

> Not sure if this is even a desired path to take, just wanted to throw the
idea out there.
Looking at the idea, I like the new "method modifiers". But it would be a
much bigger scope to tackle right now.

Best regards,
Erick

Reply via email to