More extensive UPGRADING
authorNikita Popov <nikic@php.net>
Fri, 13 Feb 2015 19:49:22 +0000 (20:49 +0100)
committerNikita Popov <nikic@php.net>
Fri, 13 Feb 2015 19:52:55 +0000 (20:52 +0100)
I'd like UPGRADING to have a complete list of changes including
code samples and suggested changes. Right now it's only a list
of bullet points, where it is often required to read a linked
RFC to understand the difference.

UPGRADING

index f992e1bfa478b99083088d687acf04997d2b2e5f..ef8714f8e1c561dd2bb73e70a1272e40b76b243e 100644 (file)
--- a/UPGRADING
+++ b/UPGRADING
@@ -21,32 +21,207 @@ PHP X.Y UPGRADE NOTES
 1. Backward Incompatible Changes
 ========================================
 
-- Core
-  . list() now always supports ArrayAccess and never supports strings.
-    Previously both were accepted in some situations and not in others.
-    (RFC: https://wiki.php.net/rfc/fix_list_behavior_inconsistency)
-  . Bitwise shifts by negative numbers of bits are disallowed (throws E_WARNING
-    and gives FALSE, like a division by zero).
-  . Left bitwise shifts by a number of bits beyond the bit width of an integer
-    will always result in 0, even on CPUs which wrap around.
-  . Right bitwise shifts by a number of bits beyond the bit width of an integer
-    will always result in 0 or -1 (depending on sign), even on CPUs which wrap
-    around.
+Core
+====
+
+Changes to variable handling
+----------------------------
+
+* Indirect variable, property and method references are now interpreted with
+  left-to-right semantics. Some examples:
+
+      $$foo['bar']['baz'] // interpreted as ($$foo)['bar']['baz']
+      $foo->$bar['baz']   // interpreted as ($foo->$bar)['baz']
+      $foo->$bar['baz']() // interpreted as ($foo->$bar)['baz']()
+      Foo::$bar['baz']()  // interpreted as (Foo::$bar)['baz']()
+
+  To restore the previous behavior add explicit curly braces:
+
+      ${$foo['bar']['baz']}
+      $foo->{$bar['baz']}
+      $foo->{$bar['baz']}()
+      Foo::{$bar['baz']}()
+      
+* The global keyword now only accepts simple variables. Instead of
+
+      global $$foo->bar;
+
+  it is now required to write the following:
+
+      global ${$foo->bar};
+
+* Parentheses around variables or function calls no longer have any influence
+  on behavior. For example the following code, where the result of a function
+  call is passed to a by-reference function
+
+      function getArray() { return [1, 2, 3]; }
+
+      $last = array_pop(getArray());
+      // Strict Standards: Only variables should be passed by reference
+      $last = array_pop((getArray()));
+      // Strict Standards: Only variables should be passed by reference
+
+  will now throw a strict standards error irregardless of whether parentheses
+  are used. Previously no notice was generated in the second case.
+
+* Array elements or object properties that are automatically created during
+  by-reference assignments will now result in a different order. For example
+
+      $array = [];
+      $array["a"] =& $array["b"];
+      $array["b"] = 1;
+      var_dump($array);
+
+  now results in the array ["a" => 1, "b" => 1], while previously the result
+  was ["b" => 1, "a" => 1];
+
+Relevant RFCs:
+ * https://wiki.php.net/rfc/uniform_variable_syntax
+ * https://wiki.php.net/rfc/abstract_syntax_tree
+
+Changes to list()
+-----------------
+
+* list() will no longer assign variables in reverse order. For example
+
+      list($array[], $array[], $array[]) = [1, 2, 3];
+      var_dump($array);
+
+  will now result in $array == [1, 2, 3] rather than [3, 2, 1]. Note that only
+  the **order** of the assignments changed, but the assigned values stay the
+  same. E.g. a normal usage like
+
+      list($a, $b, $c) = [1, 2, 3];
+      // $a = 1; $b = 2; $c = 3;
+  
+  will retain its current behavior.
+
+* Empty list() assignments are no longer allowed. As such all of the following
+  are invalid:
+
+      list() = $a;
+      list(,,) = $a;
+      list($x, list(), $y) = $a;
+
+* list() no longer supports unpacking strings (while previously this was only
+  supported in some cases). The code
+
+      $string = "xy";
+      list($x, $y) = $string;
+
+  will now result in $x == null and $y == null (without notices) instead of
+  $x == "x" and $y == "y". Furthermore list() is now always guaranteed to
+  work with objects implementing ArrayAccess, e.g.
+
+      list($a, $b) = (object) new ArrayObject([0, 1]);
+
+  will now result in $a == 0 and $b == 1. Previously both $a and $b were null.
+
+Relevant RFCs:
+* https://wiki.php.net/rfc/abstract_syntax_tree#changes_to_list
+* https://wiki.php.net/rfc/fix_list_behavior_inconsistency
+
+Changes to parameter handling
+-----------------------------
+
+* It is no longer possible to define two function parameters with the same name.
+  For example, the following method will trigger a compile-time error:
+
+      public function foo($a, $b, $unused, $unused) {
+          // ...
+      }
+
+  Code like this should be changed to use distinct parameter names, for example:
+
+      public function foo($a, $b, $unused1, $unused2) {
+          // ...
+      }
+
+* The func_get_arg() and func_get_args() functions will no longer return the
+  original value that was passed to a parameter and will instead provide the
+  current value (which might have been modified). For example
+
+      function foo($x) {
+          $x++;
+          var_dump(func_get_arg(0));
+      }
+      foo(1);
+
+  will now print "2" instead of "1". This code should be changed to either
+  perform modifications only after calling func_get_arg(s)
+
+      function foo($x) {
+          var_dump(func_get_arg(0));
+          $x++;
+      }
+
+  or avoid modifying the parameters altogether:
+
+      function foo($x) {
+          $newX = $x + 1;
+          var_dump(func_get_arg(0));
+      }
+
+* Similarly exception backtraces will no longer display the original value that
+  was passed to a function and show the modified value instead. For example
+
+      function foo($x) {
+          $x = 42;
+          throw new Exception;
+      }
+      foo("string");
+
+  will now result in the stack trace
+
+      Stack trace:
+      #0 file.php(4): foo(42)
+      #1 {main}
+
+  while previously it was:
+
+      Stack trace:
+      #0 file.php(4): foo('string')
+      #1 {main}
+
+  While this should not impact runtime behavior of your code, it is worthwhile
+  to be aware of this difference for debugging purposes.
+
+  The same limitation also applies to debug_backtrace() and other functions
+  inspecting function arguments.
+
+Relevant RFC: https://wiki.php.net/phpng
+
+Changes to integer operations
+-----------------------------
+
+* Bitwise shifts by negative numbers will now throw a warning and return false:
+
+      var_dump(1 >> -1); // bool(false)
+      // Warning: Bit shift by negative number
+
+* Left bitwise shifts by a number of bits beyond the bit width of an integer
+  will always result in 0:
+
+      var_dump(1 << 64); // int(0)
+
+  Previously the behavior of this code was dependent on the used CPU
+  architecture. For example on x86 (including x86-64) the result was int(1),
+  because the shift operand was wrapped.
+
+* Similarly right bitwise shifts by a number of bits beyond the bit width of an
+  integer will always result in 0 or -1 (depending on sign):
+
+      var_dump(1 >> 64);   // int(0)
+      var_dump(-1) >> 64); // int(-1)
+
+Relevant RFC: https://wiki.php.net/rfc/integer_semantics
+
+Other core changes
+------------------
+
   . Removed ASP (<%) and script (<script language=php>) tags.
     (RFC: https://wiki.php.net/rfc/remove_alternative_php_tags)
   . call_user_method() and call_user_method_array() no longer exists.
-  . PHP 7 doesn't keep original values of arguments passed to user functions,
-    so func_get_arg() and func_get_args() will return current value of argument
-    instead of the actually passed. The following code is going to be affected:
-    function foo($x) { $x = 2; return func_get_arg(0);} var_dump(foo(1));
-    It will now produce 2, not 1.
-  . Function parameters with duplicate name are not allowed anymore. Definitions
-    like “function foo($x,$x) {}” will lead to compile time error.
-  . Indirect variable, property and method references are now interpreted with
-    left-to-right semantics. See details in:
-       https://wiki.php.net/rfc/uniform_variable_syntax#semantic_differences_in_existing_syntax 
-  . The global keyword now only accepts simple variables. See details in:
-    https://wiki.php.net/rfc/uniform_variable_syntax#global_keyword_takes_only_simple_variables
   . The addition of Unicode Codepoint Escape Syntax for double-quoted strings
     and heredocs means that \u{ followed by an invalid sequence will now error.
     However, \u without a following { is unaffected, so "\u202e" won't error and
@@ -74,6 +249,9 @@ PHP X.Y UPGRADE NOTES
     (RFC: https://wiki.php.net/rfc/remove_hex_support_in_numeric_strings)
   . $HTTP_RAW_POST_DATA is no longer available. Use the php://input stream instead.
 
+Other
+=====
+
 - Date:
   . Removed $is_dst parameter from mktime() and gmmktime().