Re: Final variables
| From: | Marco Pivetta | Date: | Thu, 29 Jun 2017 10:14:17 +0000 |
| Subject: | Re: Final variables | ||
| References: | 1 2 3 4 5 6 7 8 9 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-99679@lists.php.net to get a copy of this message | ||
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 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
>
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 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
>
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());
https://3v4l.org/UPVWF
Hope that clarifies it.
Marco Pivetta
http://twitter.com/Ocramius
http://ocramius.github.com/