Hello internals,
Java supports the "final" keyword before a variable to determines that this
variables never change it reference. If I declare a variable as "final", I
can only initialize that once, then I could not change it after (but I can
manipulate the instance, without issues).
There some special reason to PHP doesn't supports things like that?
final $number = 123;
$number = 456; // Error: you change change final variables.
final $object = new stdClass;
$object->allowed = true; // No error.
This feature make sense because it tells to dev that the variable value
could not be updated directly (new reference). Which make easy to identify
when a variable is modifiable or not.
It is valid for a RFC?
- It can uses the "final" keyword;
- It doesn't a BC;
I too think that a final variable can be useful to make some internal
improvements on language (but it could be a BC for PHP internals). I mean,
as the variable could not be modified, then it don't need be a "flexible"
type internally (I guess that it is a zval, right?).
Reference: https://github.com/kalessil/phpinspectionsea/issues/363
--
David Rodrigues
Hi David
2017-06-28 18:10 GMT+02:00 David Rodrigues david.proweb@gmail.com:
Hello internals,
Java supports the "final" keyword before a variable to determines that this
variables never change it reference. If I declare a variable as "final", I
can only initialize that once, then I could not change it after (but I can
manipulate the instance, without issues).There some special reason to PHP doesn't supports things like that?
It seems like what you are looking for here is actually a constant[1].
However constants do not support non scalar types, such as array or
objects, what would really solve it on the objects side of things
would be the introduction of a "readonly" keyword or similar, like
that of C#[2]
final $number = 123;
$number = 456; // Error: you change change final variables.final $object = new stdClass;
$object->allowed = true; // No error.This feature make sense because it tells to dev that the variable value
could not be updated directly (new reference). Which make easy to identify
when a variable is modifiable or not.It is valid for a RFC?
- It can uses the "final" keyword;
- It doesn't a BC;
Anything is usually valid for an RFC, however I think (personally)
that this should rather be an RFC for a readonly keyword if anything
I too think that a final variable can be useful to make some internal
improvements on language (but it could be a BC for PHP internals). I mean,
as the variable could not be modified, then it don't need be a "flexible"
type internally (I guess that it is a zval, right?).Reference: https://github.com/kalessil/phpinspectionsea/issues/363
--
David Rodrigues
[1] http://php.net/constants
[2] https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/readonly
--
regards,
Kalle Sommer Nielsen
kalle@php.net
2017-06-28 18:59 GMT+02:00 Kalle Sommer Nielsen kalle@php.net:
Hi David
2017-06-28 18:10 GMT+02:00 David Rodrigues david.proweb@gmail.com:
Hello internals,
Java supports the "final" keyword before a variable to determines that
this
variables never change it reference. If I declare a variable as "final",
I
can only initialize that once, then I could not change it after (but I
can
manipulate the instance, without issues).There some special reason to PHP doesn't supports things like that?
It seems like what you are looking for here is actually a constant[1].
However constants do not support non scalar types, such as array or
objects,
Arrays are supported, but not objects.
Regards, Niklas
what would really solve it on the objects side of things
would be the introduction of a "readonly" keyword or similar, like
that of C#[2]final $number = 123;
$number = 456; // Error: you change change final variables.final $object = new stdClass;
$object->allowed = true; // No error.This feature make sense because it tells to dev that the variable value
could not be updated directly (new reference). Which make easy to
identify
when a variable is modifiable or not.It is valid for a RFC?
- It can uses the "final" keyword;
- It doesn't a BC;
Anything is usually valid for an RFC, however I think (personally)
that this should rather be an RFC for a readonly keyword if anythingI too think that a final variable can be useful to make some internal
improvements on language (but it could be a BC for PHP internals). I
mean,
as the variable could not be modified, then it don't need be a "flexible"
type internally (I guess that it is a zval, right?).Reference: https://github.com/kalessil/phpinspectionsea/issues/363
--
David Rodrigues[1] http://php.net/constants
[2] https://docs.microsoft.com/en-us/dotnet/csharp/language-
reference/keywords/readonly--
regards,Kalle Sommer Nielsen
kalle@php.net
2017-06-28 19:37 GMT+02:00 Niklas Keller me@kelunik.com:
Arrays are supported, but not objects.
Ah yes ofcourse, my apologies.
--
regards,
Kalle Sommer Nielsen
kalle@php.net
2017-06-28 13:59 GMT-03:00 Kalle Sommer Nielsen kalle@php.net:
Hi David
It seems like what you are looking for here is actually a constant[1].
However constants do not support non scalar types, such as array or
objects, what would really solve it on the objects side of things
would be the introduction of a "readonly" keyword or similar, like
that of C#[2]
Not on reality. :(
The "final" keyworks make a "local scope" variable value "blocked to
rewrite" after instantiate it.
Okay, it sounds like a "const", and it is, but "not as we known it".
While constants are class member (or globals), a final variable is just a
variable blocked to rewrite, and it could be initialized with a new data
content every time that the context is called (eg. a function).
For instance (note that the parameter is "final", then I can't modify the
parameter variable, but it can receives a new value each time that I call
this function):
function write(final $message) { echo $message; }
write("Hello");
write("World");
// Write "Hello World" on ouput.
Or then:
function randomNumber() {
final $number = mt_rand()
;
echo $number;
// $number = mt_rand_again(); // <-- will not be allowed!
}
randomNumber();
// Write "0.123"
randomNumber();
// Write "0.456"
[1] http://php.net/constants
[2] https://docs.microsoft.com/en-us/dotnet/csharp/language-
reference/keywords/readonly
--
David Rodrigues
Walter Parker walterp@gmail.com
wrote:
Constant may not have been the right word (or idea), but I agree with
Kalle. We should use readonly as the keyword here and not final as the
keyword. We can keep the same scoping rules so the following would work:
> function randomNumber() {
>
*readonly *$number =mt_rand()
;
I agree that "readonly" is a better keyword, but we have to points here:
- "final" is used on some language (Java, C++ I guess);
- "final" keyword does exists on PHP with a "similar" behaviour;
If we can implements "readonly" is good too, because turn it more implicit.
2017-06-28 15:46 GMT-03:00 David Rodrigues david.proweb@gmail.com:
2017-06-28 13:59 GMT-03:00 Kalle Sommer Nielsen kalle@php.net:
Hi David
It seems like what you are looking for here is actually a constant[1].
However constants do not support non scalar types, such as array or
objects, what would really solve it on the objects side of things
would be the introduction of a "readonly" keyword or similar, like
that of C#[2]
Not on reality. :(
The "final" keyworks make a "local scope" variable value "blocked to
rewrite" after instantiate it.
Okay, it sounds like a "const", and it is, but "not as we known it".While constants are class member (or globals), a final variable is just a
variable blocked to rewrite, and it could be initialized with a new data
content every time that the context is called (eg. a function).For instance (note that the parameter is "final", then I can't modify the
parameter variable, but it can receives a new value each time that I call
this function):function write(final $message) { echo $message; }
write("Hello");
write("World");
// Write "Hello World" on ouput.Or then:
function randomNumber() {
final $number =mt_rand()
;
echo $number;// $number = mt_rand_again(); // <-- will not be allowed!
}
randomNumber();
// Write "0.123"
randomNumber();
// Write "0.456"
[1] http://php.net/constants
[2] https://docs.microsoft.com/en-us/dotnet/csharp/language-refe
rence/keywords/readonly--
David Rodrigues
--
David Rodrigues
2017-06-29 1:07 GMT+02:00 David Rodrigues david.proweb@gmail.com:
readonly $number =
mt_rand()
;
I agree that "readonly" is a better keyword, but we have to points here:
- "final" is used on some language (Java, C++ I guess);
- "final" keyword does exists on PHP with a "similar" behaviour;
If we can implements "readonly" is good too, because turn it more implicit.
True we could re-use the final keyword, but think about it this way,
we got final methods and final classes which means it cannot be
overridden/extended respectively, if the final keyword then would also
apply to variables but it would mean they could not be written to,
that would create a WTF-factor.
The readonly keyword would work for any visibility modifiers, so
inherited classes or extending classes may read a protected property,
but not modify it as well:
class A {
protected readonly $b;
public function __construct() {
$this->b = 'C';
}
}
class B extends A {
public function read() {
echo $this->b;
}
public function write() {
$this->b = 'D';
}
}
$b = new B;
$b->read(); // "C"
$b->write(); // <- error
--
regards,
Kalle Sommer Nielsen
kalle@php.net
The final
modifier would likely clash with property type definitions, if
those ever make it to the language.
Still, a few pain-points remain:
- References to properties (you cannot reference final properties anymore,
and that is effectively a BC break for anything using reflection and
closure scope binding) - Arrays and resources as properties
- Named (Factory) constructors
- Property nullability - how do you define if a property was written to
the "last valid time" before freezing it - Unset properties and providing an alternative mechanism to distinguish
"uninitiated", "undefined" and "frozen" in he event of final properties
usage, without breaking current property access semantics
This is the exact same set of problems we had with the typed properties
RFC, and which caused the RFC to fail: please take all these in
consideration while designing the feature.
2017-06-29 1:07 GMT+02:00 David Rodrigues david.proweb@gmail.com:
readonly $number =
mt_rand()
;
I agree that "readonly" is a better keyword, but we have to points here:
- "final" is used on some language (Java, C++ I guess);
- "final" keyword does exists on PHP with a "similar" behaviour;
If we can implements "readonly" is good too, because turn it more
implicit.
True we could re-use the final keyword, but think about it this way,
we got final methods and final classes which means it cannot be
overridden/extended respectively, if the final keyword then would also
apply to variables but it would mean they could not be written to,
that would create a WTF-factor.The readonly keyword would work for any visibility modifiers, so
inherited classes or extending classes may read a protected property,
but not modify it as well:class A {
protected readonly $b;public function __construct() {
$this->b = 'C';
}
}class B extends A {
public function read() {
echo $this->b;
}public function write() {
$this->b = 'D';
}
}$b = new B;
$b->read(); // "C"
$b->write(); // <- error--
regards,Kalle Sommer Nielsen
kalle@php.net
References to properties ...is effectively a BC break for anything
using reflection and closure scope binding
No it's not.
If that feature was brought into PHP, any code that is currently
valid, that the library is capable of reflecting, would still be valid
code, that the library would still be capable of reflecting.
Yes, there would be some new syntax which the library wouldn't be
aware of, which wouldn't be supported in the library, but that is not
a BC break.
Adding new syntax to a language does mean that people who have
libraries that inspect code based on the current syntax would need to
choose between:
-
Updating the library to support the new syntax, or asking for a PR for that.
-
Saying that the library can inspect code up to the version before
the new syntax was introduced, but doesn't support later code.
I can see that would be annoying for the authors of those libraries,
as they would obviously prefer to not have to make that choice, but it
isn't a BC break.
snip - lots of difficult to solve technical problems
This is the exact same set of problems we had with the typed properties
RFC, and which caused the RFC to fail: please take all these in
consideration while designing the feature.
Yup. I think any discussion without at least some kind of plan for
dealing with the technical problems for implementing this isn't likely
to be productive.
cheers
Dan
Hey Dan,
On Thu, Jun 29, 2017 at 12:07 PM, Dan Ackroyd danack@basereality.com
wrote:
References to properties ...is effectively a BC break for anything
using reflection and closure scope bindingNo it's not.
If that feature was brought into PHP, any code that is currently
valid, that the library is capable of reflecting, would still be valid
code, that the library would still be capable of reflecting.
We discussed this before: any library designed around the capability of
dealing with a generic object would break in these scenarios, which is why
I always bring it up. It needs to be considered in an RFC, including
possible mitigation and alternatives.
Marco Pivetta
Hi
2017-06-28 20:46 GMT+02:00 David Rodrigues david.proweb@gmail.com:
The "final" keyworks make a "local scope" variable value "blocked to
rewrite" after instantiate it.
Okay, it sounds like a "const", and it is, but "not as we known it".
I get that, but I still don't understand why you would forcefully need
it to be a variable still then if you know the value is gonna be
constant, of course besides global visibility or in iterations
--
regards,
Kalle Sommer Nielsen
kalle@php.net
Am 29.06.2017 um 04:50 schrieb Kalle Sommer Nielsen:
2017-06-28 20:46 GMT+02:00 David Rodrigues david.proweb@gmail.com:
The "final" keyworks make a "local scope" variable value "blocked to
rewrite" after instantiate it.
Okay, it sounds like a "const", and it is, but "not as we known it".I get that, but I still don't understand why you would forcefully need
it to be a variable still then if you know the value is gonna be
constant, of course besides global visibility or in iterations
because constants are expensive in PHP when "define()" is a function
call and "const" is very limited for no good reason
"no good reason" because if it really would be compile time the
following won't work and so why can't you use 'const' within a
if-statement when you in fact can CONCAT two with define()
set constant
which are part of a if-statement themself
if(PHP_SAPI !== 'cli')
{
define('MY_PHP_SELF', $_SERVER['SCRIPT_NAME']);
define('rh_serverurl', PROTOCOL_PREFIX . MY_SERVER_NAME . $rh_port);
}
else
{
define('MY_PHP_SELF', '/' . basename($_SERVER['SCRIPT_NAME']));
define('rh_serverurl', 'http://localhost');
}
const rh_phpself = rh_serverurl . MY_PHP_SELF;
Final is about having immutable data. Immutable doesn't mean that it's a
system wide constant, it means that it's referentially pure in its scope.
Am 29.06.2017 um 04:50 schrieb Kalle Sommer Nielsen:
2017-06-28 20:46 GMT+02:00 David Rodrigues david.proweb@gmail.com:
The "final" keyworks make a "local scope" variable value "blocked to
rewrite" after instantiate it.
Okay, it sounds like a "const", and it is, but "not as we known it".I get that, but I still don't understand why you would forcefully need
it to be a variable still then if you know the value is gonna be
constant, of course besides global visibility or in iterationsbecause constants are expensive in PHP when "define()" is a function call
and "const" is very limited for no good reason"no good reason" because if it really would be compile time the following
won't work and so why can't you use 'const' within a if-statement when you
in fact can CONCAT two withdefine()
set constant which are part of a
if-statement themself
if(PHP_SAPI !== 'cli')
{
define('MY_PHP_SELF', $_SERVER['SCRIPT_NAME']);
define('rh_serverurl', PROTOCOL_PREFIX . MY_SERVER_NAME . $rh_port);
}
else
{
define('MY_PHP_SELF', '/' . basename($_SERVER['SCRIPT_NAME']));
define('rh_serverurl', 'http://localhost');
}
const rh_phpself = rh_serverurl . MY_PHP_SELF;
Am 29.06.2017 um 11:08 schrieb Marco Pivetta:
Final is about having immutable data. Immutable doesn't mean that it's a
system wide constant, it means that it's referentially pure in its scope.
i refered to "why you would forcefully need it to be a variable still
then if you know the value is gonna be constant" and as long constants
in PHP are a) very expensive and b) "const" pretends to be compile time
which is provable wrong with my sample code are terrible to use
in other languages like Visual Basic constants are fast, in PHP they are
slow, both in define and access
On 29 Jun 2017 11:05 AM, "lists@rhsoft.net mailto:lists@rhsoft.net"
<lists@rhsoft.net mailto:lists@rhsoft.net> wrote:Am 29.06.2017 um 04:50 schrieb Kalle Sommer Nielsen: 2017-06-28 20:46 GMT+02:00 David Rodrigues <david.proweb@gmail.com <mailto:david.proweb@gmail.com>>: The "final" keyworks make a "local scope" variable value "blocked to rewrite" after instantiate it. Okay, it sounds like a "const", and it is, but "not as we known it". I get that, but I still don't understand why you would forcefully need it to be a variable still then if you know the value is gonna be constant, of course besides global visibility or in iterations because constants are expensive in PHP when "define()" is a function call and "const" is very limited for no good reason "no good reason" because if it really would be compile time the following won't work and so why can't you use 'const' within a if-statement when you in fact can CONCAT two with `define()` set constant which are part of a if-statement themself ____________________________________________________ if(PHP_SAPI !== 'cli') { define('MY_PHP_SELF', $_SERVER['SCRIPT_NAME']); define('rh_serverurl', PROTOCOL_PREFIX . MY_SERVER_NAME . $rh_port); } else { define('MY_PHP_SELF', '/' . basename($_SERVER['SCRIPT_NAME'])); define('rh_serverurl', 'http://localhost'); } const rh_phpself = rh_serverurl . MY_PHP_SELF;
in other languages like Visual Basic constants are fast, in PHP they are
slow, both in define and access
Two things here:
- don't ever consider visual basic for any comparison of any sort: it's
basically (ha!) the worst example of a programming language that I can
think of before malborge - speed is not relevant in this scope: program correctness is. Final
properties would allow switching value object representations from accessor
(getter) based logic (extremely slow) to public property based (less
overhead, also in writing).
Marco Pivetta
Am 29.06.2017 um 11:25 schrieb Marco Pivetta:
On Thu, Jun 29, 2017 at 11:19 AM, lists@rhsoft.net
mailto:lists@rhsoft.net <lists@rhsoft.net mailto:lists@rhsoft.net>
wrote:in other languages like Visual Basic constants are fast, in PHP they are slow, both in define and access
Two things here:
- don't ever consider visual basic for any comparison of any sort:
it's basically (ha!) the worst example of a programming language that I
can think of before malborge
stop it - many people say the same about PHP
- speed is not relevant in this scope: program correctness is. Final
properties would allow switching value object representations from
accessor (getter) based logic (extremely slow) to public property based
(less overhead, also in writing)
in which scope is speed not relevant?
depends on your application, in my scopes i try to avoid expensive
opcodes and useless function calls, program correctness is a completly
different thing and it's not one or the other but both
I will try answer the questions:
I get that, but I still don't understand why you would forcefully need
it to be a variable still then if you know the value is gonna be
constant, of course besides global visibility or in iterations
"final" is not "const". "final" mean a initial state that will never be
modified, but it could be initialized with different values on same
runtime. It is like I say "my name is David and will be all the time David
when I am on an informal context" and "my name is Rodrigues and will be all
the time Rodrigues when I am on a forma context", on same "document".
https://pastebin.com/QCrmrZQe
True we could re-use the final keyword, but think about it this way,
we got final methods and final classes which means it cannot be
overridden/extended respectively, if the final keyword then would also
apply to variables but it would mean they could not be written to,
that would create a WTF-factor.
It is done on Java, for instance. We can use "final" on classes or
functions that mean that it cannot be overrided, or "final" in variables,
that mean that it cannot be re-referenced (rewrite after initialization).
And not seems strange to me. We could "abstract the term" to understand
that in any of cases (for classes, function or variables) the information
could not be overrided after defined.
The readonly keyword would work for any visibility modifiers, so
inherited classes or extending classes may read a protected property,
but not modify it as well:
For me, the readonly keyword should be implemented on future to another
case: make a public property writeable only by the own class. But it is for
another discussion.
The
final
modifier would likely clash with property type definitions,
if those ever make it to the language.
Still, a few pain-points remain:
- References to properties (you cannot reference final properties
anymore, and that is effectively a BC break for anything using reflection
and closure scope binding)
I don't know if I understand, but for properties you could redefine a final
property on constructor (as Java). https://pastebin.com/bTZcUT33
- Arrays and resources as properties
You can modify arrays or resources on final variables, since that you don't
modify the reference. https://pastebin.com/D38wL8x7
- Named (Factory) constructors
I don't understand.
- Property nullability - how do you define if a property was written to
the "last valid time" before freezing it
Because PHP don't have support to "variable initialization" (eg. "$name;")
then you should only initializate it when you will write the initial (and
freezed) value. https://pastebin.com/Ua6DFUC1
- Unset properties and providing an alternative mechanism to distinguish
"uninitiated", "undefined" and "frozen" in he event of final properties
usage, without breaking current property access semantics
It will be modified. Final variables still are a variable, but with the
status that "never change after initializate" (a flag). We can just
implement a new reflection method to properties to identify if it
isFinal(), or even for variables like "is_final($var)". By other side, this
last doesn't make sense because the final variable is just a "code
documentation" to the own dev knows that is not allowed modify it anymore.
Maybe we need implements that only for ReflectionProperty (first case),
because it could be part of a code that the user have not modify access
(eg. vendor code). https://pastebin.com/jSjNQACd
2017-06-29 6:25 GMT-03:00 Marco Pivetta ocramius@gmail.com:
On Thu, Jun 29, 2017 at 11:19 AM, lists@rhsoft.net lists@rhsoft.net
wrote:in other languages like Visual Basic constants are fast, in PHP they are
slow, both in define and accessTwo things here:
- don't ever consider visual basic for any comparison of any sort: it's
basically (ha!) the worst example of a programming language that I can
think of before malborge- speed is not relevant in this scope: program correctness is. Final
properties would allow switching value object representations from accessor
(getter) based logic (extremely slow) to public property based (less
overhead, also in writing).Marco Pivetta
--
David Rodrigues
Hi David,
On Thu, Jun 29, 2017 at 11:58 AM, David Rodrigues david.proweb@gmail.com
wrote:
The
final
modifier would likely clash with property type definitions,
if those ever make it to the language.
Still, a few pain-points remain:
- References to properties (you cannot reference final properties
anymore, and that is effectively a BC break for anything using reflection
and closure scope binding)I don't know if I understand, but for properties you could redefine a
final property on constructor (as Java). https://pastebin.com/bTZcUT33
No, the problem is following:
class Foo { final public $bar = 'baz'; }
$foo = new Foo;
$bar = & $foo->bar;
$bar = 'taz';
var_dump($foo->bar);
This kind of ugly code will break.
- Arrays and resources as properties
You can modify arrays or resources on final variables, since that you
don't modify the reference. https://pastebin.com/D38wL8x7
That doesn't make it "final", although I get your point, and yes, it
basically prevents decreasing the reference count on that particular
property. I think this kills the usefulness of the feature, but it's indeed
still useful.
- Named (Factory) constructors
I don't understand.
Relatively common pattern:
class Foo {
private final $bar;
private function __construct() { /* hammertime */ }
public static function create($something) : self {
$instance = new self();
$instance->bar = $something;
return $instance;
}
}
See also http://verraes.net/2014/06/named-constructors-in-php/
- Property nullability - how do you define if a property was written to
the "last valid time" before freezing itBecause PHP don't have support to "variable initialization" (eg. "$name;")
then you should only initializate it when you will write the initial (and
freezed) value. https://pastebin.com/Ua6DFUC1
Got it, so a "first write" would be equivalent to a freeze operation? When
do you seal the property if the value isn't overwritten? Would you disable
default values for properties that are declared final
?
- Unset properties and providing an alternative mechanism to
distinguish "uninitiated", "undefined" and "frozen" in he event of final
properties usage, without breaking current property access semanticsIt will be modified. Final variables still are a variable, but with the
status that "never change after initializate" (a flag). We can just
implement a new reflection method to properties to identify if it
isFinal(), or even for variables like "is_final($var)". By other side, this
last doesn't make sense because the final variable is just a "code
documentation" to the own dev knows that is not allowed modify it anymore.
Maybe we need implements that only for ReflectionProperty (first case),
because it could be part of a code that the user have not modify access
(eg. vendor code). https://pastebin.com/jSjNQACd
The reflection API is a given, but the problem is still the same:
class Foo {
private final $foo;
private $lazyLoad;
public function saySomething() {
return 'Saying ' . $this->foo;
}
private function __construct() {
}
public static function new() : self {
$instance = new self();
$instance->foo = 'something';
return $instance;
}
public static function newLazy() : self {
$instance = new self();
$instance->lazyLoad = function () use ($instance) {
$instance->foo = 'something lazy';
};
unset($instance->foo);
return $instance;
}
public function __get($name) {
($this->lazyLoad)();
return $this->foo;
}
}
$foo = Foo::new();
var_dump($foo->saySomething());
$lazyFoo = Foo::newLazy();
var_dump($lazyFoo->saySomething());
Hope that clarifies it.
Marco Pivetta