rfc:object-initializer

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
rfc:object-initializer [2019/09/12 13:33] – Added bc brzuchalrfc:object-initializer [2019/10/24 07:36] (current) – closing vote, moving to declined brzuchal
Line 2: Line 2:
   * Version: 1.0   * Version: 1.0
   * Date: 2019-09-03   * Date: 2019-09-03
-  * Author: Michał Brzuchalski <michal.brzuchalski@gmail.com+  * Author: Michał Brzuchalski <brzuchal@php.net
-  * Status: Draft+  * Status: Declined
   * First Published at: http://wiki.php.net/rfc/object-initializer    * First Published at: http://wiki.php.net/rfc/object-initializer 
- 
- 
  
 ===== Introduction ===== ===== Introduction =====
Line 15: Line 13:
   - Pass created a fully initialized object.   - Pass created a fully initialized object.
  
-That's where object initializer optimization can benefit with single expression statement and it can be used to initialize any kind of object //(including anonymous classes)//. The initializer block can use any properties and variables available in the containing scope, but one has to be wary of the fact that initializers are run after constructors.+In current PHP implementation with Typed Properties, it is possible to instantiate class which doesn't require nullability for all properties and when they're not initialized we finish with 
 +properties in an uninitialized state. 
 + 
 +That's where object initializer optimization can benefit with single expression statement and it can be used to initialize any kind of object //(including anonymous classes)// ensuring all 
 +required properties are properly initialized, otherwise a ''RuntimeExpection'' is thrown 
 + 
 +The initializer block can use any properties and variables available in the containing scope, but one has to be wary of the fact that initializers are run after constructors.
  
 ===== Proposal ===== ===== Proposal =====
 Object initializers allow assigning values to any accessible properties of an object at creation time without having to invoke a constructor followed by lines of assignment statements. The object initializer syntax enables to specify arguments for a constructor or omit the arguments (and parentheses syntax). Object initializers allow assigning values to any accessible properties of an object at creation time without having to invoke a constructor followed by lines of assignment statements. The object initializer syntax enables to specify arguments for a constructor or omit the arguments (and parentheses syntax).
- 
-The following example shows how to use an object initializer with a //Customer//, //Car// and how to invoke the parameterless constructor. 
  
 <code php> <code php>
Line 36: Line 38:
   }   }
 } }
- 
-$customer = new Customer { 
-  id = 123, 
-  name = "John Doe", 
-}; 
  
 class Car class Car
Line 47: Line 44:
   public string $vin;   public string $vin;
 } }
 +</code>
 +
 +The following example shows how to use an object initializer with a ''Customer'', ''Car'' and how to invoke the parameterless constructor.
 +
 +<code php>
 +<?php
 +
 +$customer = new Customer {
 +  id = 123,
 +  name = "John Doe",
 +};
  
 $car = new Car { $car = new Car {
Line 54: Line 62:
 </code> </code>
  
-The object initializers syntax allows to create an instanceand after that, it assigns the newly created objectwith its assigned properties, to the variable in the assignment.+> **Note!** If in current scope there are constants with exactly the same name as property names used in the above examplethey do not impact object initialization in any way. Property names used in Object Initializer block stay with no relation to constants names.
  
-Above example is an equivalent to the previous one.+The following example is equivalent to the previous one.
  
 <code php> <code php>
Line 72: Line 80:
 The main difference is that object initializers allow creating a new object, with its assigned properties in a single expression. For eg. factory methods where normally a significant amount of argument has default values or simple Data Transfer Objects could benefit. The main difference is that object initializers allow creating a new object, with its assigned properties in a single expression. For eg. factory methods where normally a significant amount of argument has default values or simple Data Transfer Objects could benefit.
  
-> Note! Currently, language allows instantiating object and initializing only a subset of typed non-nullable properties without a default value. These rules apply to object initializer the same way, meaning the creation of properly initialized object state is in authors responsibility, cause object initializer is a simplification as mentioned before.+**Note!** Currently, language allows instantiating object and initializing only a subset of typed non-nullable properties without a default value. These rules apply to object initializer the same way, meaning the creation of properly initialized object state is in authors responsibility, cause object initializer is a simplification as mentioned before.
  
-==== Constructors ====+==== Restrictions ==== 
 +Using Object Initializer enforce that if a class is instantiated with the Object Initializer, at the end of the instantiation and properties initialization, all visible properties //(depends on initialization scope)// are initialized, otherwise, a ''RuntimeException'' is thrown.  
 +This helps to avoid bugs where a property is added to the class but forgot to be assigned it a value in all cases where the class is instantiated and initialized. 
  
-Due to the fact that initializer block purpose is a simplification of instantiating and initializing object properties, constructors are called before initialization takes apart. Constructors allow initializing default values //(especially not scalar one properties like `DateTimeetc.)// for read-only properties which are visible only in the class scope.+The object initializers syntax allows to create an instance, and after that, it assigns the newly created object, with its assigned properties, to the variable in the assignment. 
 + 
 +<code php> 
 +<?php 
 + 
 +$customer = new Customer { 
 +  name = "John Doe", 
 +}; // throws RuntimeException: Initialization of Customer class object failed due to missing required properties 
 + 
 +$car = new Car { 
 +  yearOfProduction = 2019, 
 +}; // throws RuntimeException: Initialization of Car class object failed due to missing required properties 
 +</code> 
 + 
 + 
 +==== Constructors ==== 
 +Due to the fact that initializer block purpose is a simplification of instantiating and initializing object properties, constructors are called before initialization takes apart. Constructors allow initializing default values //(especially not scalar one properties like ''DateTime'' etc.)// for read-only properties which are visible only in the class scope.
  
 Due to the fact that objects in PHP simply have constructor directly declared in class definition or indirectly through the defaulting constructor, creating a class instance and initializing properties through initializer block will effect in invoking constructor and assign property values after instantiation. Due to the fact that objects in PHP simply have constructor directly declared in class definition or indirectly through the defaulting constructor, creating a class instance and initializing properties through initializer block will effect in invoking constructor and assign property values after instantiation.
 +
 +> **Note!** Object instantiation allows only constructors without required arguments to be used. Any class which requires passing arguments to constructor cannot be used in combination with object initializer. 
 +
  
 <code php> <code php>
Line 103: Line 132:
  
  
-> Note! Classes without constructor desired to mimick "structs" or "data classes" are almost completely viable through the class with typed properties which means they rather don't need a constructor declared directly in the definition of class.+**Note!** Classes without constructor desired to mimick "structs" or "data classes" are almost completely viable through the class with typed properties which means they rather don't need a constructor declared directly in the definition of class.
  
-> Note! If a class needs validation upon to validate its invariants a proper validation logic needs to be called after initialization. To combine it with object initializer and keep the validation process encapsulated, instantiation and initialization of class state are possible in named constructor with validation invoke before the instance is being used.+**Note!** If a class needs validation upon to validate its invariants a proper validation logic needs to be called after initialization. To combine it with object initializer and keep the validation process encapsulated, instantiation and initialization of class state are possible in named constructor with validation invoke before the instance is being used.
  
 ==== Lexical scope ==== ==== Lexical scope ====
Line 115: Line 144:
 Initializer block allows assigning values to properties accessible from the current class context. This means if used to initialize object properties from inside the same class like for eg. using named static constructor all standard visibility rules apply as it is just a simplification of object creation and assigning values statements. Initializer block allows assigning values to properties accessible from the current class context. This means if used to initialize object properties from inside the same class like for eg. using named static constructor all standard visibility rules apply as it is just a simplification of object creation and assigning values statements.
  
-Above example shows the correct behaviour of visibility rules.+The following example shows the correct behaviour of visibility rules.
  
 <code php> <code php>
Line 175: Line 204:
 Initializer block stands instead of constructor arguments which means in case of anonymous classes that place is right before the class definition. Initializer block stands instead of constructor arguments which means in case of anonymous classes that place is right before the class definition.
  
-Above example shows how to use object initializer with anonymous classes.+The following example shows how to use object initializer with anonymous classes.
  
 <code php> <code php>
Line 194: Line 223:
 Dynamic properties can be set by their name or by a variable which holds the name of property. Dynamic properties can be set by their name or by a variable which holds the name of property.
  
-Above example shows how to use object initializer with dynamic properties.+The following example shows how to use object initializer with dynamic properties.
  
 <code php> <code php>
Line 205: Line 234:
 }; };
 </code> </code>
- 
- 
  
 ===== Backward Incompatible Changes ===== ===== Backward Incompatible Changes =====
-This proposal changes the meaning of above example which uses curly brace to fetch array offset //(which is already deprecated since PHP 7.4)// which is very rare usage.+This proposal changes the meaning of the above example which uses curly brace to fetch array offset //(which is already deprecated since PHP 7.4)// which is very rare usage.
  
 <code php> <code php>
Line 217: Line 244:
 $foo = [123 => Foo::class]; $foo = [123 => Foo::class];
 new $foo { new $foo {
-  $var =123+  $var = 123
 }; };
 +</code>
 +
 +===== Reflection =====
 +Both ''ReflectionClass'' and ''ReflectionObject'' get a new method ''newInstanceFields(array $fields): object''.
 +
 +<code php>
 +<?php
 +
 +$reflectionClass = new ReflectionClass(Customer::class);
 +$customer = $reflectionClass->newInstanceFields(['name' => 'Bert']);
 +// equivalent to
 +$customer = new Customer {name = 'Bert'};
 </code> </code>
  
Line 266: Line 305:
 As this is a language change, a 2/3 majority is required. As this is a language change, a 2/3 majority is required.
  
-The vote is a straight Yes/No vote for accepting the RFC and merging the patch.+The vote is a straight Yes/No vote for accepting the RFC. 
 + 
 +<doodle title="Accept object initializer?" auth="brzuchal" voteType="single" closed="true"> 
 +   * Yes 
 +   * No 
 +</doodle> 
 +
 +<doodle title="Choose between two tokens as an assign operator in object initializer block?" auth="brzuchal" voteType="single" closed="true"> 
 +   * = 
 +   * => 
 +</doodle> 
  
 ===== Patches and Tests ===== ===== Patches and Tests =====
rfc/object-initializer.1568295195.txt.gz · Last modified: 2019/09/12 13:33 by brzuchal