Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:123695 X-Original-To: internals@lists.php.net Delivered-To: internals@lists.php.net Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5]) by qa.php.net (Postfix) with ESMTPS id 35D201A009C for ; Thu, 20 Jun 2024 13:01:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1718888579; bh=ndkDhnRHDxkvtvcxPE4Ql3Z67YC6JBFgWL4SrOiRcb8=; h=References:In-Reply-To:From:Date:Subject:To:From; b=HB4ltciVRUAmckf8zfr4orAiAjLNrGlF9hwyr7y4+8TGilgEWBAzMAOAe2VnOSamY g3cqauIq60S1/suaVG6KOHQPFMKNylde65FhcR0tN2I6oqZT9Wa6es0RTw8JEthk/p uV5YDNyX8vNlDvK9DzuEByvV4iClp9p02Lc/0uKXhcwgV8QM0fotqF4za+TRHv4iKH UCA57FRJ74W2SqyoRF5+2cLD8OeqZu4b400DaoFz1MlmHQ/ApFjnoYKEU4khXTsIxU NUrZoEkh28yJGIqqi5+QIzaZ10UarYOEIBIDXH7ByFIv22GBT8mcBQLmSVTz726PwI rDGMyUDKiEthw== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id C83E5180078 for ; Thu, 20 Jun 2024 13:02:58 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.0 (2022-12-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=0.6 required=5.0 tests=BAYES_50,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,FREEMAIL_FROM, HTML_MESSAGE,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE, SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: Error (Cannot connect to unix socket '/var/run/clamav/clamd.ctl': connect: Connection refused) X-Envelope-From: Received: from mail-qt1-f171.google.com (mail-qt1-f171.google.com [209.85.160.171]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Thu, 20 Jun 2024 13:02:58 +0000 (UTC) Received: by mail-qt1-f171.google.com with SMTP id d75a77b69052e-4415e623653so14582161cf.1 for ; Thu, 20 Jun 2024 06:01:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1718888503; x=1719493303; darn=lists.php.net; h=to:subject:message-id:date:from:in-reply-to:references:mime-version :from:to:cc:subject:date:message-id:reply-to; bh=5wQs2DJ/EVDmJJgMM/lcZSklV8zyDdezwz11wJa3rH4=; b=YJhdSe9facsAR7K8PBmSoM09pJdlK8OUE1YZ5TY9k0UNGFLrhzawIB5ikmPErOMZ1g NLI9MdEYOKfL2MTyD7nY6PbE7sx5M+2NnO7zGZq2yBGb3+wwQ57PIQXJDJWf0hmcEu5r seT0JCwePDJ7t6QrA4eZIZLuTXTGzgIbSOo1Eiq3XR5jw7J9hIINDFWb54hFBLbcFC7L aYg5KAungPjT3SI3Ad0CvzlXAocosPKKk5InJSFODHkGqObwVVh9gnHfEh/88Ozz+iBU KzVVHxHQX8sPF95StjP6ghtm7ZRAMfT/KAND7s9zffdHxyPHkdvvI7cki2giwjhXrUUL 57eA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718888503; x=1719493303; h=to:subject:message-id:date:from:in-reply-to:references:mime-version :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=5wQs2DJ/EVDmJJgMM/lcZSklV8zyDdezwz11wJa3rH4=; b=DTf8KOdHZ8b5QKWBkiHZvXmqGq4/N1m9F2WU/Woblnz4ZVk/gtZSCw5a165yBzYSLC daj77U+aDrXcojnD/jAEZbYolREfMQaSw/TfHOsSiXcm315OK7x1lPrnbYFOfJb0p0Wl N2zmp9FCW0ltM6fp16pEi21jyGg4UM85LarmEUhJzO4ncAyA3ZPq+l+41/Nyo6+DJo00 skQzdn2sSIlALCdmIXG1d5/WfYtOGpxUbpIklLw9N2mSRfsSDyCt8rWx9I7/N3T4Tb7w zuqqLbSUR/2tPIvJyp68hn38Oz33XBFv6oJEFAelOCPTfXS+I9UW271SX2xqVV+f6cF5 +++w== X-Gm-Message-State: AOJu0YwqyOhOI+diN9KvoAPOcwl6f4JO5fFhrQwuwvK9LENAeuoWUhDz 6aLE5tT8G9sLnGWpSHsmbssqlQzsYUW/gc0FFMyRp3WKKnYOTzdBo4h+O1+o63uPFnXCaYUhA35 9Vaqvf7KfruW1PyS2mfnhqcDdD+nkVg== X-Google-Smtp-Source: AGHT+IHFAniuOs+qtPpJU3FzEVrlecutuVPFBDP+gHzsP6J5emrSB0+5x5AGDv9IcCBh3SHbSsrgeBBLRnKUKyZ8abE= X-Received: by 2002:a05:6214:252f:b0:6b5:198e:353d with SMTP id 6a1803df08f44-6b5198e3859mr5475676d6.10.1718888502752; Thu, 20 Jun 2024 06:01:42 -0700 (PDT) Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net MIME-Version: 1.0 References: In-Reply-To: Date: Thu, 20 Jun 2024 10:01:06 -0300 Message-ID: Subject: Re: [PHP-DEV] [RFC] Static Constructor To: php internals Content-Type: multipart/alternative; boundary="0000000000009d80e5061b51eabc" From: ericklima.comp@gmail.com (Erick de Azevedo Lima) --0000000000009d80e5061b51eabc Content-Type: text/plain; charset="UTF-8" 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 --0000000000009d80e5061b51eabc Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Hi all.

Answering to Larry:<= br>
> More complex initialization of things like lookup tables= or "dynamic=20 constants" (like if you wanted to record "now" to use for la= ter=20 comparisons).
Those are my use cases, to be honest.
> For that reason, therefore, I don't like the current approach,=20 especially for this line: "Programmers have the option to call the=20 __staticConstruct method to reset static properties values if desired."= ;
I just laughed at myself when I read this. As I said, my ma= in 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 i= t's a consensus to remove it, I'll gladly do it. :-)

> Yo= ur examples would be clearer if you leveraged the ??=3D operator, which=20 would reduce your initializeMinDate() methods to a single line.
Y= es, 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 a= s possible.
In this case, it was to emphasize the fact that we mu= st implement a logic to check (the "if" at the beginning of the m= ethod) if the property was already initialized.

&g= t; What I object to is holding up Java as being "stricter about OO=20 principles."=C2=A0 OO principles are not a uniform, monolithic thing.<= /div>
> In=20 fact, the person who invented the term Object-Oriented has said before=20 that C++ and Java are *not* what he had in mind.
> "Class= based=20 programming" is not what OOP was intended to be.
To be = honest, when I wrote this part, I was indeed thinking about "class bas= ed" programming.
And Java is stricter than PHP and C++ in th= is sense: It does not have loose functions, everything must be inside a cla= ss.
And even though "Class based=20 programming" is not what OOP was intended to be, it's what's m= ostly found out there: OOP =3D Class based programming
But my mai= n 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=20 for you in a Go playground. Hopefully you can include Go's approach in= =20 your RFC?
No, I'm not familiar enough with Go to provide exam= ples, so I did not consider it. As you provided the example, I'll gladl= y include it. Thank you!

> To elaborate more about &qu= ot;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 sugge= st `__constructStatic()`. This matches the existing naming
> pattern= of `__callStatic()` being the companion to `__call()`.
Noted. I&= #39;m not really attached to any name and your point makes a lot of sense.<= br>

Ilija:

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

> This makes the initialization= order
> unpredictable, because static properties are initialized lazily when>=20 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
{
=C2=A0 =C2=A0 private static \DateTimeInt= erface $v1;

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

=C2=A0 =C2=A0 private static function __staticConstruct= ()
=C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 self::$v1 =3D new \Dat= eTimeImmutable('2024-06-19 00:00:00');
=C2=A0 =C2=A0 =C2=A0 =C2= =A0 echo 'calling ' . __METHOD__ . PHP_EOL;
=C2=A0 =C2=A0 =C2=A0= =C2=A0 echo C2::USING_SYMBOL_DECLARED_LATER . PHP_EOL;
=C2=A0 =C2=A0 }<= br>
=C2=A0 =C2=A0 public static function getV1()
=C2=A0 =C2=A0 {
= =C2=A0 =C2=A0 =C2=A0 =C2=A0 echo 'Before accessing C1::$v1 variable'= ; . PHP_EOL;

=C2=A0 =C2=A0 =C2=A0 =C2=A0 return self::$v1;
=C2=A0= =C2=A0 }
}

class C2
{
=C2=A0 =C2=A0 public const USING_SYM= BOL_DECLARED_LATER =3D 'C2::USING_SYMBOL_DECLARED_LATER';
}
<= br>$obj1 =3D new C1(); //should not trigger zend_class_init_statics()
echo C1::getV1()->format('Y-m-d') . PHP_EOL; //

This ex= ample prints:

C1::__constructBefore accessing C1::$v1 variable
calling C1::__staticConstruct
C2::= USING_SYMBOL_DECLARED_LATER
2024-06-19

> Lazy evaluation might be ok if order is clearly defined. Making the=
> order undefined makes it hard (or impossible) to understand which<= br>> symbols declared in the current file may be used from __static_cons= truct()
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 a= pproach is here.
One of my fir= st 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 ca= ses.

Mike again:

> Consid= er that some uses for a static function need to always occur=20 no matter
> whether or not any other method of the class is ca= lled. My=20 previous email [1] covered several.
> Here [2] is a discu= ssion on StackOverflow of "hooks" that should be eagerly loaded.<= /div>
Yes, I considered this approach before. But then I realized= that for covering the properties initialization,
this alrea= dy 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 implemen= ted maybe using another magic method, like "__load" or "__li= nk",
which would be hooks on class loading process and not s= pecific to static variables initialization

Lynn:

> Not sure if this is even a desired path to tak= e, 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 re= gards,
Erick
--0000000000009d80e5061b51eabc--