Hi,
finally I managed to do my first RFC draft.
https://wiki.php.net/rfc/static_class_constructor
I hope I have done everything correct so far and I'm looking forward to
your feedback on it.
As I already mentioned in the prediscussion thread here:
For being my first change to the PHP core, I would be very happy, if
someone of the "old stager" would help me with the implementation of
this RFC if it is accepted.
Regards
--
DerOetzi
Hi,
finally I managed to do my first RFC draft.
https://wiki.php.net/rfc/static_class_constructor
I hope I have done everything correct so far and I'm looking forward to
your feedback on it.
In my opinion this makes the language way more complex as there are more
places which "suddenly" execute code but solves a small problem compared
to that. (Which actually is an issue many people would suggest to avoid
completely instead of ennobling this with a language feature.
Why am I saying it makes the language more complex? - Your proposal
seems to miss mentioning when exactly the method is executed. what is
the output of
a.php:
<?php
echo 'A: '.FILE.':'.LINE."\n";
class A {
static function __static() {
echo CLASS.'::'.METHOD."\n";
}
}
echo 'B: '.FILE.':'.LINE."\n";
class B {
static function __static() {
echo CLASS.'::'.METHOD."\n";
}
}
echo 'C: '.FILE.':'.LINE."\n";
?>
b.php:
<?php
echo 'D: '.FILE.':'.LINE."\n";
C::$foo = 23;
echo 'E: '.FILE.':'.LINE."\n";
include 'a.php';
echo 'F: '.FILE.':'.LINE."\n";
class C {
static $foo = 0;
static function __static() {
echo CLASS.'::'.METHOD."\n";
}
}
echo 'G: '.FILE.':'.LINE."\n";
class D extends B {
static function __static() {
echo CLASS.'::'.METHOD."\n";
}
}
echo 'H: '.FILE.':'.LINE."\n";
?>
Mind that in b.php we make use of class C above the declaration, which
we can do as C is a simple class and can be bound early during
compilation. Class D however can only be bound during run-time, after
including a.php, which happens after C was already used.
johannes
What would happen if you "call the parent constructor":
class A extends B {
static public function __static() {
B::__static();
}
}
On Mon, Apr 13, 2015 at 5:23 PM, Johannes Schlüter johannes@schlueters.de
wrote:
Hi,
finally I managed to do my first RFC draft.
https://wiki.php.net/rfc/static_class_constructor
I hope I have done everything correct so far and I'm looking forward to
your feedback on it.In my opinion this makes the language way more complex as there are more
places which "suddenly" execute code but solves a small problem compared
to that. (Which actually is an issue many people would suggest to avoid
completely instead of ennobling this with a language feature.Why am I saying it makes the language more complex? - Your proposal
seems to miss mentioning when exactly the method is executed. what is
the output ofa.php:
<?php
echo 'A: '.FILE.':'.LINE."\n";
class A {
static function __static() {
echo CLASS.'::'.METHOD."\n";
}
}
echo 'B: '.FILE.':'.LINE."\n";
class B {
static function __static() {
echo CLASS.'::'.METHOD."\n";
}
}
echo 'C: '.FILE.':'.LINE."\n";
?>b.php:
<?php
echo 'D: '.FILE.':'.LINE."\n";C::$foo = 23;
echo 'E: '.FILE.':'.LINE."\n";include 'a.php';
echo 'F: '.FILE.':'.LINE."\n";class C {
static $foo = 0;
static function __static() {
echo CLASS.'::'.METHOD."\n";
}
}echo 'G: '.FILE.':'.LINE."\n";
class D extends B {
static function __static() {
echo CLASS.'::'.METHOD."\n";
}
}echo 'H: '.FILE.':'.LINE."\n";
?>Mind that in b.php we make use of class C above the declaration, which
we can do as C is a simple class and can be bound early during
compilation. Class D however can only be bound during run-time, after
including a.php, which happens after C was already used.johannes
Am 13.04.2015 um 17:29 schrieb Benjamin Eberlei:
What would happen if you "call the parent constructor":
class A extends B {
static public function __static() {
B::__static();
}
}
Please have a closer look to the definition of the function:
https://wiki.php.net/rfc/static_class_constructor#proposal
it should be declared "private" to prohibit any access from outside the
of the class itself.
Although see the the answer 2 in discussion section:
https://wiki.php.net/rfc/static_class_constructor#inheritance_of_the_class_constructor
Thanks for feedback
On Mon, Apr 13, 2015 at 5:23 PM, Johannes Schlüter johannes@schlueters.de
wrote:Hi,
finally I managed to do my first RFC draft.
https://wiki.php.net/rfc/static_class_constructor
I hope I have done everything correct so far and I'm looking forward to
your feedback on it.In my opinion this makes the language way more complex as there are more
places which "suddenly" execute code but solves a small problem compared
to that. (Which actually is an issue many people would suggest to avoid
completely instead of ennobling this with a language feature.Why am I saying it makes the language more complex? - Your proposal
seems to miss mentioning when exactly the method is executed. what is
the output ofa.php:
<?php
echo 'A: '.FILE.':'.LINE."\n";
class A {
static function __static() {
echo CLASS.'::'.METHOD."\n";
}
}
echo 'B: '.FILE.':'.LINE."\n";
class B {
static function __static() {
echo CLASS.'::'.METHOD."\n";
}
}
echo 'C: '.FILE.':'.LINE."\n";
?>b.php:
<?php
echo 'D: '.FILE.':'.LINE."\n";C::$foo = 23;
echo 'E: '.FILE.':'.LINE."\n";include 'a.php';
echo 'F: '.FILE.':'.LINE."\n";class C {
static $foo = 0;
static function __static() {
echo CLASS.'::'.METHOD."\n";
}
}echo 'G: '.FILE.':'.LINE."\n";
class D extends B {
static function __static() {
echo CLASS.'::'.METHOD."\n";
}
}echo 'H: '.FILE.':'.LINE."\n";
?>Mind that in b.php we make use of class C above the declaration, which
we can do as C is a simple class and can be bound early during
compilation. Class D however can only be bound during run-time, after
including a.php, which happens after C was already used.johannes
--
DerOetzi
Why am I saying it makes the language more complex? - Your proposal
seems to miss mentioning when exactly the method is executed. what is
Ah, I missed this
Trigger for “magic” method call: First call to class, either
first call to __construct(...) or first call to any public or
protected static method or property of the class
Which means adding a flag, which has to be checked on every method call
or other access to any class and leads to completely "random" (from
perspective of average user) behavior while this feature can't be used
for an "obvious" task like registering itself as plugin into some
registry.
-1
johannes
Am 13.04.2015 um 18:54 schrieb Johannes Schlüter:
Why am I saying it makes the language more complex? - Your proposal
seems to miss mentioning when exactly the method is executed. what isAh, I missed this
Trigger for “magic” method call: First call to class, either first call to __construct(...) or first call to any public or protected static method or property of the class
Which means adding a flag, which has to be checked on every method call
or other access to any class and leads to completely "random" (from
perspective of average user) behavior while this feature can't be used
for an "obvious" task like registering itself as plugin into some
registry.-1
johannes
The obvious task is to initial the state of the class before usage as I
wrote inside my introduction of the RFC.
I think there is no "random" behavior (not more then other so called
"magic" methods). But I see that I forgot this point in the discussion
part because we already had this point on the prediscussion. Will add
this tomorrow, with my exact answer to this point,
Thanks for reminder.
https://wiki.php.net/rfc/static_class_constructor
--
DerOetzi
The obvious task is to initial the state of the class before usage as I
wrote inside my introduction of the RFC.
That is one possible task users are going to try doing. Users are more
creative.
I think there is no "random" behavior (not more then other so called
"magic" methods). But I see that I forgot this point in the discussion
part because we already had this point on the prediscussion. Will add
this tomorrow, with my exact answer to this point,
It is "random" in the sense that a seemingly unrelated change somewhere
in an application changes order in other places, too.
johannes
De : Johannes Ott [mailto:mail@deroetzi.de]
finally I managed to do my first RFC draft.https://wiki.php.net/rfc/static_class_constructor
I hope I have done everything correct so far and I'm looking forward to
your feedback on it.
Interesting. It also allows to respect PSR-1, which says 'Files SHOULD either declare symbols (classes, functions, constants, etc.) or cause side-effects (e.g. generate output, change .ini settings, etc.) but SHOULD NOT do both' (see https://github.com/flaupretre/automap/blob/develop/src/classes/Automap.php for an example).
Comments :
-
__static is ambiguous and does not reflect the method's role. Even if longer, I definitely prefer __staticInit or, even better, __classInit.
-
IMO, the method should be called when the class is created, just after every parent class and implemented interfaces are created. If some load a bunch of classes they don't use, that's their problem, not ours. It is not a reason to follow a two-step process. A properly written program uses autoloading and loads the classes it needs only. Another argument is that I'm not sure it is possible to catch every case of read access to static properties.
-
I think you should provide a destructor method because there can be a need to cleanup/close the resources opened when initializing the class. It can be open files, sockets, or any other resource, but, IMO, they need to be explicitly closed when the request ends.
Regards
François
Am 13.04.2015 um 18:02 schrieb François Laupretre:
De : Johannes Ott [mailto:mail@deroetzi.de]
finally I managed to do my first RFC draft.https://wiki.php.net/rfc/static_class_constructor
I hope I have done everything correct so far and I'm looking forward to
your feedback on it.Interesting. It also allows to respect PSR-1, which says 'Files SHOULD either declare symbols (classes, functions, constants, etc.) or cause side-effects (e.g. generate output, change .ini settings, etc.) but SHOULD NOT do both' (see https://github.com/flaupretre/automap/blob/develop/src/classes/Automap.php for an example).
Comments :
- __static is ambiguous and does not reflect the method's role. Even if longer, I definitely prefer __staticInit or, even better, __classInit.
Okay I will think about the alternative names, I somehow like
__classInit you proposed or __classConstruct
- IMO, the method should be called when the class is created, just after every parent class and implemented interfaces are created. If some load a bunch of classes they don't use, that's their problem, not ours. It is not a reason to follow a two-step process. A properly written program uses autoloading and loads the classes it needs only. Another argument is that I'm not sure it is possible to catch every case of read access to static properties.
On the one hand I think we should respect most of the user-land code as
far as possible and on the other hand I think there should be the
possibility to handle the being initialized or not initialized inside
the class action.
- I think you should provide a destructor method because there can be a need to cleanup/close the resources opened when initializing the class. It can be open files, sockets, or any other resource, but, IMO, they need to be explicitly closed when the request ends.
Please see my answer 4 in discussion section for this:
Regards
François
--
DerOetzi
Okay I will think about the alternative names, I somehow like
__classInit you proposed or __classConstruct
I like simple: __init()
- IMO, the method should be called when the class is created, just after every parent class and implemented interfaces are created.
In general I think static class data and static class constructors are
a sign of poorly designed code, which means I am against this feature.
If it does make it though I agree with this statement above. The
behavior proposed in the RFC makes it non-obvious when the class
constructor is run and would much prefer it happening immediately
after definition.
Am 14.04.2015 um 00:16 schrieb Levi Morrison:
- IMO, the method should be called when the class is created, just after every parent class and implemented interfaces are created.
In general I think static class data and static class constructors are
a sign of poorly designed code, which means I am against this feature.
Thanks for the flowers as we would say in Germany! I didn't hear I'm
doing poor code for a long time now :(
--
DerOetzi
Am 14.04.2015 um 00:16 schrieb Levi Morrison:
- IMO, the method should be called when the class is created, just after every parent class and implemented interfaces are created.
In general I think static class data and static class constructors are
a sign of poorly designed code, which means I am against this feature.Thanks for the flowers as we would say in Germany! I didn't hear I'm
doing poor code for a long time now :(
If static elements need initialisation they apparently have state. If
they have state they in 95% of the cases shouldn't be static but bound
to an object instance. Yes there might be cases where this is a good
design, but the language should provide the syntax sugar to lead the 95%
to write good code instead of leading them to write bad code which can
be tested harder and where changes might have unexpected side-effects.
So even if you're code is good and your own use-case is good design,
which I won't question, I don't think advertising it to all users by
providing a language feature is good.
johannes
Am 13.04.2015 um 18:48 schrieb Cesar Rodas:
Instead of having a method, why don't we allow body expr to be
evaluated as we see things in the Class definition?<?php
class foobar
{
static protected $conn = new mysqli('localhost', 'my_user',
'my_password', 'my_db');
}It's cleaner but it breaks compatibility with everything :-(
--
César D. Rodas
Open Source developer
+595-983-161124
PGP: F9ED A265 A3AB C8A1 D145 7368 158A 0336 C707 0AA6
Hello César,
you accidently wrote this answer only to me, so I forward this to the
mailing list together with my answer.
First of all I would not store any resource handle, like a mysql
connection you did in your example, directly to a static member. (Will
add another point on this to the discussion-section the next days)
https://wiki.php.net/rfc/static_class_constructor#discussions
Second point is that with your suggested syntax only single methods can
be used to initialize the static member. With my proposal you will be
able to do more complex initialization algorithms. For example open a
config-file with fopen, read the content to a static member and close
the config-file again with fclose.
Regards
--
DerOetzi
Hi,
finally I managed to do my first RFC draft.
https://wiki.php.net/rfc/static_class_constructor
I hope I have done everything correct so far and I'm looking forward to
your feedback on it.
The static constructor cannot be called by the user, which means it
shouldn't even register as a function. Additionally, it is always
private. Given these constraints I would prefer to change this syntax:
class Config {
private static $arIni;
private static function __static() {
$self::$arIni = parse_ini_file('config.ini');
}
}
To this (borrowed from Java):
class Config {
private static $arIni;
static {
$self::$arIni = parse_ini_file('config.ini');
}
}
I do not see any reason to do the former unless the latter has
conflicts in the parser, which I don't think it would.
Hi,
2015-04-13 10:37 GMT-03:00 Johannes Ott mail@deroetzi.de:
Hi,
finally I managed to do my first RFC draft.
https://wiki.php.net/rfc/static_class_constructor
I hope I have done everything correct so far and I'm looking forward to
your feedback on it.As I already mentioned in the prediscussion thread here:
For being my first change to the PHP core, I would be very happy, if
someone of the "old stager" would help me with the implementation of
this RFC if it is accepted.Regards
--
DerOetzi--
I know this is still a draft, but conceptually I don't like this
feature. I always avoid static
state on classes as much as possible and I think this should be
avoided. But this is my
personal opinion. Some suggestions:
In case the RFC passes, I'd prefer to have a static{ ... }
block
instead of yet
another static __ method. The reason is that this kind of construct is
already known
on other languages as static{...}
and that feels more organized IMMO.
In case you decide to proceed with the magic method approach, I'd
prefer the more
verbose __staticConstruct
name because it seems clearer.
Thanks,
Márcio
As the RFC is still in draft status, I will stop for now answering any
issues on the purpose of this RFC. I will now rewrite some things at the
draft, and come back to the discussion in this threads after those changes
I will focus on the following open issues I have identified during the
last two days discussion here.
I identified the follwing issues to clearify more:
- "Magic" method vs. static block (as it is done by JAVA)
- Naming of the method
- Why the trigger should be like it is proposed by the RFC
And I will focus again on the contra arguments during last days
discussion and the pre-draft discussion some weeks ago. In my point of
view all of those arguments I read so far can be summarized to the
single argument:
You should avoid static class state and for this a initialization
method, because this is "poor" designed code and "crucial" things can be
done with it.
Please feel free to correct me, if I got anyone's argument against the
RFC wrong!
I hope I can finish the changes to the drafts during the weekend,
afterwards I will answer your comments just by linking to the specific
RFC-Section.
Thanks and regards
--
DerOetzi
Hi Johannes,
Hi,
finally I managed to do my first RFC draft.
https://wiki.php.net/rfc/static_class_constructor
I hope I have done everything correct so far and I'm looking forward to
your feedback on it.
Here is some feedback then:
From the RFC:
- Trigger for “magic” method call: First call to class, either first call to __construct(...) or first call to any public or protected static method or property of the class
I don't think this doesn't cover all cases that it needs to. For
example calling unserialze on some data that results in a class that
has this static initializer should mean that it would be invoked?
Similarly ReflectionClass::newInstanceWithoutConstructor also creates
a class in a way that isn't covered in the RFC, but presumably should
be.
From the RFC.
the static class constructor should be able to throw a catchable Exception
for user error handling, if it is not possible to initialize. The open issue for
me is, what the behavior on recalling the static class constructor afterward is.
There are two possible behaviors I do not know which one I really would prefer so far.
You missed the third and in my opinion correct one; the static
initializer would only ever be called once. If the programmer catches
the exception and forces the program to continue, that is their own
problem. Adding complexity to a language to try to work around
programmers ignoring exceptions is not a good idea.
I think the RFC needs to be clearer in the specification of the order
that static initialization is called in. e.g. class B extends class A.
Both A and B have static initialization blocks. When a user calls new B()
which static initialization block is called first?
cheers
Dan
Am 14.04.2015 um 16:33 schrieb Dan Ackroyd:
Here is some feedback then:
From the RFC:
- Trigger for “magic” method call: First call to class, either first call to __construct(...) or first call to any public or protected static method or property of the class
I don't think this doesn't cover all cases that it needs to. For
example calling unserialze on some data that results in a class that
has this static initializer should mean that it would be invoked?
Similarly ReflectionClass::newInstanceWithoutConstructor also creates
a class in a way that isn't covered in the RFC, but presumably should
be.
Your correct I forgot this two scenarios of first calls to a class.
Thanks for the hint!
But in the new draft (v0.4) I'm preparing at the moment I'll try to
formulate the trigger "first call" more common by comparing it to the
same trigger for __autoload function. Then these two scenarios should be
included as well.
From the RFC.
the static class constructor should be able to throw a catchable Exception
for user error handling, if it is not possible to initialize. The open issue for
me is, what the behavior on recalling the static class constructor afterward is.
There are two possible behaviors I do not know which one I really would prefer so far.You missed the third and in my opinion correct one; the static
initializer would only ever be called once.
I think this is suggested behaviour 1, isn't it?
"On recall of the static class constructor a fatal error is raised to
ensure it is only called once..."
If the programmer catches
the exception and forces the program to continue, that is their own
problem. Adding complexity to a language to try to work around
programmers ignoring exceptions is not a good idea.
I agree to this point that ignoring an exception is a bad idea. I think
the example-code is a bit confusing, because the empty catch-block gives
the impression that the exception is ignored. But what is really meant
by behaviour 2 is that the programmer has the opportunity to handle the
exception not by exiting his programm, but by cleaning up the
situation and afterwards retry the code which failed before.
I will try to clearify this in one of the next draft versions.
I think the RFC needs to be clearer in the specification of the order
that static initialization is called in. e.g. class B extends class A.
Both A and B have static initialization blocks. When a user callsnew B()
which static initialization block is called first?
While rewriting the draft for v0.4 I although noticed this gap inside
specification and came to the conclusion that this is the third "first
call" scenario I haved missed. Because inheritance by using keyword
extends is already a first call to class A.
cheers
Dan
Thanks for really constructive feedback, that one really helps me for
the next draft of rfc
Regards
--
DerOetzi
Am 14.04.2015 um 16:33 schrieb Dan Ackroyd:
Here is some feedback then:
Johannes Ott wrote:
But in the new draft (v0.4) I'm preparing at the moment I'll try to
formulate the trigger "first call" more common by comparing it to the
same trigger for __autoload function.
Hmm. The language will need to be quite clear then - sometimes classes
are autoloaded when they aren't instantiated. e.g. for just normal
reflection of classes, the class is autoloaded if it isn't already
present, or some people may autoload all the things ahead of time, to
avoid any delay when responding to a request.
Johannes Ott wrote:
Danack wrote:
You missed the third and in my opinion correct one; the static
initializer would only ever be called once.
I think this is suggested behaviour 1, isn't it?
I read that section very differntly.
"On recall of the static class constructor a fatal error is raised to
ensure it is only called once and initialized before exception was
thrown properties will not be reinitialized."
I read that as it implies that it would be possible to call the static
initializer again, and in that case a fatal error would be thrown. If
the initializer is only ever called once, it would be clearer to say
that as a 'positive' statement, as opposed to saying a 'negative' of
what wouldn't be allowed - i.e. single statements are clearer than any
kind of double-negative statements.
Johannes Ott wrote:
Danack wrote:
I think the RFC needs to be clearer in the specification of the order
that static initialization is called in.
Because inheritance by using keyword
extends is already a first call to class A.
tbh, it's quite likely that looking at Java or some other language
that has static initializers and copying that behaviour for precedence
could be the best choice.
However the behaviour might not be mappable directly, due to
differences in PHP's inheritance and class model, in particular the
late static binding.
class A {
static function __staticInit() {
static::foo();
}
static function foo() {
echo "This is A::foo\n";
}
}
class B extends A {
static function foo() {
echo "This is B::foo\n";
}
}
B::__staticInit(); //Output is 'This is B::foo'
It's pretty easy to imagine some cases where there are circular
dependencies....so the RFC would need to be precise about exactly what
the rules are.
cheers
Dan
I would rather appreciate run-time class properties initialization.
Best regards,
Kubo2
2015-04-13 15:37 GMT+02:00 Johannes Ott mail@deroetzi.de:
Hi,
finally I managed to do my first RFC draft.
https://wiki.php.net/rfc/static_class_constructor
I hope I have done everything correct so far and I'm looking forward to
your feedback on it.As I already mentioned in the prediscussion thread here:
For being my first change to the PHP core, I would be very happy, if
someone of the "old stager" would help me with the implementation of
this RFC if it is accepted.Regards
--
DerOetzi
Am 13.04.2015 um 15:37 schrieb Johannes Ott:
Hi,
finally I managed to do my first RFC draft.
https://wiki.php.net/rfc/static_class_constructor
I hope I have done everything correct so far and I'm looking forward to
your feedback on it.As I already mentioned in the prediscussion thread here:
For being my first change to the PHP core, I would be very happy, if
someone of the "old stager" would help me with the implementation of
this RFC if it is accepted.Regards
Hi there,
there was a really bad situation in my life the last week, so I'm not
able to do anything on this Draft for some days, I will pause it for
some weeks now
Regards
--
DerOetzi
2015-04-28 11:29 GMT+03:00 Johannes Ott mail@deroetzi.de:
Am 13.04.2015 um 15:37 schrieb Johannes Ott:
Hi,
finally I managed to do my first RFC draft.
https://wiki.php.net/rfc/static_class_constructor
I hope I have done everything correct so far and I'm looking forward to
your feedback on it.As I already mentioned in the prediscussion thread here:
For being my first change to the PHP core, I would be very happy, if
someone of the "old stager" would help me with the implementation of
this RFC if it is accepted.Regards
Hi there,
there was a really bad situation in my life the last week, so I'm not
able to do anything on this Draft for some days, I will pause it for
some weeks nowRegards
--
DerOetzi--
Hi.
Is any progress on the implementation?
Thank.