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. Enjoy the weekend! Olle -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: https://www.php.net/unsub.php