kelunik

Niklas Keller

bwoebi

Bob Weinand

Contents

PHP RFC: In Operator

Introduction

This RFC adds a new in operator which simplifies contains checks for strings and arrays. The in operator makes these checks way more readable and lowers the cognitive load. Additionally, it also works for Traversable.

Motivation

Checking if a specific input in an allowed range of value is a very common check in web application, therefore this operator simplifies those checks (and besides makes them a little bit faster). Currently, we have to use in_array($needle, $haystack, true) or strpos($haystack, $needle) !== false. These functions have a inconsistent parameter order, so it's hard to remember which is the right one for each. Additionally, omitting the third parameter for in_array is very common which led to security vulnerabilities in the past.

Proposal

Add a new operator (expr1) in (expr2). It checks whether expr2 contains expr1.

It uses strict comparison (===) for array values / instances of Traversable and doesn't search recursively.

$contains = "foo" in ["a", "b", "c"]; // false
$contains = "foo" in ["foo", "bar"]; // true
$contains = "foo" in [["foo"], ["bar"]]; // false
$contains = "0e0" in ["0"]; // false, because of strict comparison
$contains = 0 in ["0"]; // false, because of strict comparison
 
$contains = ["foo"] in [["foo"], ["bar"]]; // true
$contains = ["foo"] in ["foo"]; // false

Traversables are only iterated until there's a match.

function gen () {
    yield "foo";
    yield "bar";
    // code below here wouldn't be executed if "bar" matches
    // because it stops if there's a match.
}
 
$contains = "bar" in gen(); // true
$contains = "baz" in gen(); // false

If $haystack is a string, it's a simple contains check.

$contains = "foo" in "foobar"; // true
$contains = "php" in "foobar"; // false

Other expressions than mixed in array|Traversable or string in string throw an EngineException.

Why strict?

It's strict because otherwise something like “foo” in [0] would pass.

Precedence

It should have the same precedence as instanceof, so it's possible to negate it:

if (!$input in $validValues) {
    // ...
}

Backward Incompatible Changes

New reserved keyword in. This affects function, constant and class, but not class constant and method names, because it depends on the context sensitive lexer being merged.

Proposed PHP Version(s)

Next major release, at the time of writing PHP 7.

RFC Impact

New Constants

A T_IN constant for use with ext/tokenizer has been added.

Future Scope

There could be a syntax that allows to check for multiple values at once, e.g.

$contains = ...["foo", "bar"] in ["foo", "baz", "bar"];

Patches and Tests

Rejected Features

Keep this updated with features that were discussed on the mail lists.

Versions

Version Changed Date
0.5 Removed integer support, so the strictness is consistent.
0.4 Removed possibility to check multiple values using an array.

Votes

An option needs 2/3 votes to win

Introduce the in operator? (44.7% approved)
User Vote
aharvey No
ajf No
ben Yes
bishop No
brandon Yes
bwoebi Yes
Damien Tournoud No
danack No
duodraco Yes
eliw Yes
fa No
fibbarth Yes
galvao No
indeyets Yes
irker No
jedibc Yes
jwage Yes
kinncj No
klaussilveira Yes
leigh No
lstrojny Yes
mbeccati No
mike No
mj No
ocramius No
patrickallaert No
pauloelr Yes
philstu Yes
pollita No
ralphschindler No
ramsey No
rdohms Yes
rmf Yes
salathe No
santiagolizardo Yes
sebastian No
seld Yes
stas No
stelianm No
subjective No
theseer Yes
till Yes
timo No
wiesemann Yes
yohgaki No
yunosh Yes
zeev No