On Sat, Sep 12, 2020 at 10:23 PM Olle Härstedt <olleharst...@gmail.com> wrote:
> Hi internals! > > Separation of data and behaviour is both a fun and hard discussion, > especially considering: > > * "It should be possible to add new features without touching old code"; > and > * "Principle of Least Privilege" (never expose more than you have to) > (https://en.wikipedia.org/wiki/Principle_of_least_privilege). > > There should (could) be a way to add new behaviour to old data without > touching the old data (class). Traits won't work in this use-case, > since they assume the same internal structure for all trait-using > classes. Imagine the `stringable` interface and a `toString` trait. A > __toString() method needs knowledge about the internal structure of a > class Foo. Yet if we want to keep adding behaviour to Foo, we'll end > up with either exposing too much of Foo, or expanding the class file > indefinitely. Please note that composition is not a proper solution, > since it requires exposure of Foo; composition leads to lack of proper > encapsulation, or representation exposure. > > In Haskell it's possible to split instance implementation of > type-classes into separate files. In Rust you can have a struct with > private fields and put impl of behaviour in different files (but same > crate). > > A similar feature in PHP could look like (using new keyword `expand` > but could be anything, or even `extend` in new context): > > ``` > // File FooStringable.php > expand Foo implements stringable { > public function __toString() { > // Full access to Foo's all private fields here. > // Assumes you can autoload Foo. > // Assumes usage of $foo->__toString(); will be configured with > autoload to dynamically find the correct behaviour of Foo. > } > } > ``` > > If you'd use composition instead, you'd maybe have a formatter class > with a method `$formatter->toString(stringable $foo)`. This has the > problem I mentioned with exposing too much of $foo; it breaks > encapsulation. It has the benefit of being able to provide multiple > toString methods with different formats, but would have to assume > similar structure of the objects passed to it (defined with an > interface), which is not always possible or desirable. > > The other way is inheritance, which doesn't scale over multiple > behaviours. `FooWithStringable extends Foo`? No. > > Was I clear here? Do you understand the issues that this design > pattern is trying to solve? Its purpose is to solve "keep adding new > feature to old data" in a clean and proper way, while keeping > information encapsulation. > Do I understand you correctly, it would be somewhat like "opening" up a class and making changes to it in another file? Certainly a powerful concept, but I would be very interested in the details how that would interact with autoloading. If I have a class Foo loaded, and its "extension" FooString with toString method not, then it would lead to the "toString" code missing. > > Enjoy the weekend! > Olle > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: https://www.php.net/unsub.php > >