rfc:data-classes
Differences
This shows you the differences between two versions of the page.
Next revision | Previous revision | ||
rfc:data-classes [2024/04/16 15:48] – created rfc ilutov | rfc:data-classes [2024/04/22 12:51] (current) – ilutov | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== PHP RFC: Data classes | + | Data classes |
- | + | ||
- | * Date: 2024-04-16 | + | |
- | * Author: Ilija Tovilo, tovilo.ilija@gmail.com | + | |
- | * Status: Draft | + | |
- | * Target Version: PHP 8.x | + | |
- | * Implementation: | + | |
- | + | ||
- | ===== Proposal ===== | + | |
- | + | ||
- | This RFC proposes | + | |
- | + | ||
- | < | + | |
- | data class Vector2 { | + | |
- | public function __construct( | + | |
- | public $x, | + | |
- | public $y, | + | |
- | ) {} | + | |
- | } | + | |
- | + | ||
- | $v1 = new Vector2(1, 2); | + | |
- | $v2 = $v1; | + | |
- | $v2-> | + | |
- | + | ||
- | var_dump($v1 === $v2); // false | + | |
- | + | ||
- | $v2->x--; | + | |
- | var_dump($v1 === $v2); // true | + | |
- | </ | + | |
- | + | ||
- | ===== The problem ===== | + | |
- | + | ||
- | Classes are commonly used to model data in PHP. Such classes have many names (plain old php objects, data transfer objects, | + | |
- | + | ||
- | Using classes for data comes with one significant downside: Objects are passed by reference, rather than by value. When dealing with mutable data, this makes it very easy to shoot yourself in the foot by exposing mutations to places that don't expect to see them. | + | |
- | + | ||
- | Consider the following example: | + | |
- | + | ||
- | <code php> | + | |
- | class Vector2 { | + | |
- | public function __construct( | + | |
- | public $x, | + | |
- | public $y, | + | |
- | ) {} | + | |
- | } | + | |
- | + | ||
- | function createShapes() { | + | |
- | // Use same position for both shapes | + | |
- | $vec = new Vector2(10, 20); | + | |
- | $circle = new Circle(position: | + | |
- | $square = new Square(position: | + | |
- | return [$circle, $square]; | + | |
- | } | + | |
- | + | ||
- | $shapes = createShapes(); | + | |
- | + | ||
- | function applyGravity() { | + | |
- | foreach ($shapes as $shape) { | + | |
- | /* We're not physicists. :P */ | + | |
- | $shape-> | + | |
- | } | + | |
- | } | + | |
- | + | ||
- | applyGravity($shape); | + | |
- | + | ||
- | foreach ($shapes as $shape) { | + | |
- | var_dump($shape-> | + | |
- | } | + | |
- | // Vector2(10, 18), Vector2(10, 18)?? | + | |
- | </ | + | |
- | + | ||
- | Since both shapes are created with the same position, '' | + | |
- | + | ||
- | What's the solution? '' | + | |
- | + | ||
- | What we really want is to automatically copy '' | + | |
- | + | ||
- | ===== The solution ===== | + | |
- | + | ||
- | As hinted at previously, the solution this RFC proposes is to introduce data classes, which are classes with value semantics. Like arrays, strings and other value types, data classes are // | + | |
- | + | ||
- | With this description, | + | |
- | + | ||
- | <code php> | + | |
- | data class Vector2 { ... } | + | |
- | + | ||
- | function createShapes() { | + | |
- | // Use same position for both shapes | + | |
- | $vec = new Vector2(10, 20); | + | |
- | $circle = new Circle(position: | + | |
- | $square = new Square(position: | + | |
- | return [$circle, $square]; | + | |
- | } | + | |
- | </ | + | |
- | + | ||
- | // | + | |
- | + | ||
- | ===== CoW 🐄 ===== | + | |
- | + | ||
- | But wait, this sounds familiar. | + | |
- | + | ||
- | < | + | |
- | What's the solution? '' | + | |
- | + | ||
- | < | + | |
- | </ | + | |
- | + | ||
- | You may assume that data classes will be just as slow as creating a copy for each usage of a data class. However, data classes have a cool trick up their sleeves: Copy-on-write, | + | |
- | + | ||
- | <code php> | + | |
- | function print($value) { | + | |
- | var_dump($value); | + | |
- | } | + | |
- | + | ||
- | function appendAndPrint($value) { | + | |
- | $value[] = ' | + | |
- | var_dump($value); | + | |
- | } | + | |
- | + | ||
- | print([' | + | |
- | appendAndPrint([' | + | |
- | + | ||
- | $array = [' | + | |
- | print($array); | + | |
- | appendAndPrint($array); | + | |
- | </ | + | |
- | + | ||
- | //Note:// This code ignores the fact that array literals are constant, for simplicity. | + | |
- | + | ||
- | With the rules described above, the only line performing potential copies is '' | + | |
- | + | ||
- | This is already how arrays work today. Data classes follow the exact same principle. | + | |
- | + | ||
- | <code php> | + | |
- | function print($value) { | + | |
- | var_dump($value); | + | |
- | } | + | |
- | + | ||
- | function modifyAndPrint($value) { | + | |
- | $value-> | + | |
- | var_dump($value); | + | |
- | } | + | |
- | + | ||
- | print(new Vector2(1, 2)); | + | |
- | appendAndPrint(new Vector2(1, 2)); | + | |
- | + | ||
- | $vec = new Vector2(1, 2); | + | |
- | print($vec); | + | |
- | appendAndPrint($vec); | + | |
- | </ | + | |
- | + | ||
- | Only one implicit copy happens, namely in '' | + | |
- | + | ||
- | ===== Method calls ===== | + | |
- | + | ||
- | TODO | + | |
- | + | ||
- | ===== Reflection ===== | + | |
- | + | ||
- | TODO | + | |
- | + | ||
- | ===== Future scope ===== | + | |
- | + | ||
- | - Hashing for '' | + | |
- | + | ||
- | ===== Vote ===== | + | |
- | + | ||
- | Voting starts xxxx-xx-xx and ends xxxx-xx-xx. | + | |
- | + | ||
- | As this is a language change, a 2/3 majority is required. | + | |
- | + | ||
- | <doodle title=" | + | |
- | * Yes | + | |
- | * No | + | |
- | </ | + |
rfc/data-classes.1713282528.txt.gz · Last modified: 2024/04/16 15:48 by ilutov