This is an old revision of the document!
PHP RFC: Chaining Comparison
- Version: 0.1
- Date: 2016-12-08
- Author: David Walker (dave@mudsite.com), Richard Fussenegger (php@fleshgrinder.com)
- Status: Draft
- First Published at: http://wiki.php.net/rfc/chaining_comparison
Introduction
The point of this RFC is to allow the chaining together of comparison and equality operations [==, !=, !==, ===, <, <=, >, >=
] to allow arbitrary comparisons. The initial request that spawned this RFC was for interval checking.
Today such comparisons must be written as such:
<?php $a = 10; if (0 < $a && $a < 100) { echo "Value is between 0 and 100\n"; }
The proposal of this RFC is to allow new syntax as follows:
<?php $a = 10; if (0 < $a < 100) { echo "Value is between 0 and 100\n"; }
Proposal
The proposal creates a new AST operation type ZEND_AST_COMPARE_OP
which will be compiled in a left-precedence required manor. In doing this compilation we introduce a new means of emitting an operation, by noting where a JMPZ_EX
may need to exist, depending if we are continuing the compare chain. This will shift operations that may have been emitted by compiling the right side of this AST compare to allow jumping over them if the left side of the operation is evaluated to false.
The proposal also changes the precedence of the equality, and comparison, operations to being left recursive. This is required, since if the left node of this operation is true, and it itself is a comparison operation, it should return the right node (for less than) to be used in the next comparison op. Example:
<?php $a = 1; $b = 10; var_dump($a < 5 < $b++); /* * AST Dump * AST_CALL * expr: AST_NAME * flags: NAME_NOT_FQ (1) * name: "var_dump" * args: AST_ARG_LIST * 0: AST_COMPARE_OP * flags: COMPARE_IS_SMALLER (19) * left: AST_COMPARE_OP * flags: COMPARE_IS_SMALLER (19) * left: AST_VAR * name: "a" * right: 5 * right: AST_POST_INC * var: AST_VAR * name: "b" */ /* * OPCodes * * 2 INIT_FCALL 'var_dump' * 3 IS_SMALLER ~4 !0, 5 * 4 > JMPZ_EX ~6 ~4, ->7 * 5 > POST_INC ~5 !1 * 6 > IS_SMALLER ~6 ~4, ~5 * 7 > SEND_VAL ~6 * 8 DO_ICALL */
So we can see what this feature will do internally. Speaking directly at the OPCodes we see how our JMPZ_EZ
code injection works. Since the first evaluated IS_SMALLER
op is the left side-recursive of the expression, we determine this expressions result. If the result evaluates to true (and if you look at the code it checks to see if there's an extended_value flag) we continue to the POST_INC
otherwise we skip to the sending of the value which would be false.
Backward Incompatible Changes
No BC Breaking changes expected
Proposed PHP Version(s)
Next PHP (currently 7.2)
RFC Impact
To Opcache
Yes, we're adding new JMPZ_EX codes when chaining to ensure false values correctly jump over any pre/post inc/dev ops from eval.
Open Issues
Unaffected PHP Functionality
Does not alter the operation of the comparison Spaceship [<=>] operator.
Future Scope
Proposed Voting Choices
Requires 2/3 vote
Patches and Tests
A Proposed Implementaiton: https://github.com/php/php-src/compare/master...bp1222:multi-compare
Will need eyes of those more familiar with AST/VM to review.
For changes affecting the core language, you should also provide a patch for the language specification.
Implementation
References
Initial idea on Internals: http://marc.info/?l=php-internals&m=147846422102802&w=2
Rejected Features
Keep this updated with features that were discussed on the mail lists.