9. Rules list

9.1. Introduction

9.2. $HTTP_RAW_POST_DATA

$HTTP_RAW_POST_DATA is deprecated, and should be replaced by php://input.

$HTTP_RAW_POST_DATA is deprecated since PHP 5.6.

It is possible to ready by setting always_populate_raw_post_data to -1.

<?php

// PHP 5.5 and older
$postdata = $HTTP_RAW_POST_DATA;

// PHP 5.6 and more recent
$postdata = file_get_contents(php://input);

?>

See also $HTTP_RAW_POST_DATA variable.

Short name Php/RawPostDataUsage
Themes CompatibilityPHP56

9.3. $this Belongs To Classes Or Traits

$this variable represents only the current object.

It is a pseudo-variable, and should be used within class’s or trait’s methods (except for static) and not outside.

PHP 7.1 is stricter and check for $this at several positions. Some are found by static analysis, some are dynamic analysis.

<?php

// as an argument
function foo($this) {
    // Using global
    global $this;
    // Using static (not a property)
    static $this;

    // Can't unset it
    unset($this);

    try {
        // inside a foreach
        foreach($a as $this) {  }
        foreach($a as $this => $b) {  }
        foreach($a as $b => $this) {  }
    } catch (Exception $this) {
        // inside a catch
    }

    // with Variable Variable
    $a = this;
    $$a = 42;
}

class foo {
    function bar() {
        // Using references
        $a =& $this;
        $a = 42;

        // Using 'extract(), 'parse_str() or similar functions
        extract([this => 42]);  // throw new Error(Cannot re-assign $this)
        var_dump($this);
    }

    static function '__call($name, $args) {
        // Using '__call
        var_dump($this); // prints object(C)#1 (0) {}, php-7.0 printed NULL
        $this->test();   // prints ops
    }

}
?>
Short name Classes/ThisIsForClasses
Themes Analyze

9.4. $this Is Not An Array

$this variable represents the current object and it is not an array, unless the class (or its parents) has the ‘ArrayAccess interface.

<?php

// $this is an array
class Foo extends 'ArrayAccess {
    function bar() {
        ++$this[3];
    }
}

// $this is not an array
class Foo2 {
    function bar() {
        ++$this[3];
    }
}

?>
Short name Classes/ThisIsNotAnArray
Themes Analyze

9.5. $this Is Not For Static Methods

Static methods shouldn’t use $this variable.

$this variable represents an object, the current object. It is not compatible with a static method, which may operate without any object.

While executing a static method, $this is actually set to NULL.

<?php

class foo {
    static $staticProperty = 1;

    // Static methods should use static properties
    static public function 'count() {
        return self::$staticProperty++;
    }

    // Static methods can't use $this
    static public function bar() {
        return $this->a;   // No $this usage in a static method
    }
}

?>

See also Static Keyword.

Short name Classes/ThisIsNotForStatic
Themes Analyze
ClearPHP no-static-this

9.6. ** For Exponent

PHP has the operator ‘** to provide exponents, instead of the slower function ‘pow(). This operator was introduced in PHP 5.6.

<?php
    $cube = pow(2, 3); // 8

    $cubeInPHP56 = 2 '** 3; // 8
?>

If the code needs to be backward compatible to 5.5 or less, don’t use the new operator.

See also Arithmetic Operators.

Short name Php/NewExponent
Themes Suggestions

9.7. ::class

PHP has a special class constant to hold the name of the class : ‘class’ keyword. It represents the classname that is used in the left part of the operator.

Using ‘::class’ is safer than relying on a string. It does adapt if the class’s name or its namespace is changed’. It is also faster, though it is a micro-optimisation.

It is introduced in PHP 5.5.

<?php
class foo {
    public function bar( ) {
        echo ClassName::class;
    }
}

$f = new Foo( );
$f->bar( );
// return Namespace\ClassName

?>

See also Class Constant.

Short name Php/StaticclassUsage
Themes CompatibilityPHP53, CompatibilityPHP54

9.8. @ Operator

@ is the ‘no scream’ operator : it suppresses error output.

<?php

// Set x with incoming value, or else null.
$x = @$_GET['x'];

?>

This operator is actually very slow : it will process the error all the way up, and finally decide not to display it. It is often faster to check the conditions first, then run the method without @.

You may also set display_error to 0 in the php.ini : this will avoid user’s error display, but will keep the error in the PHP logs, for later processing.

The only situation where @ is useful is when a native PHP function displays errors messages when error happens and there is no way to check it from the code.

This is the case with ‘fopen(), ‘stream_socket_server(), ‘token_get_all().

See also Error Control Operators.

Short name Structures/Noscream
Themes Analyze
ClearPHP no-noscream

9.9. Abstract Static Methods

Methods cannot be both abstract and static. Static methods belong to a class, and will not be overridden by the child class. For normal methods, PHP will start at the object level, then go up the hierarchy to find the method. With static, you have to mention the name, or use Late Static Binding, with self or static. Hence, it is useless to have an abstract static method : it should be a simple static method.

A child class is able to declare a method with the same name than a static method in the parent, but those two methods will stay independant.

This is not the case anymore in PHP 7.0+.

<?php

abstract class foo {
    // This is not possible
    static abstract function bar() ;
}

?>

See also Why does PHP 5.2+ disallow abstract static class methods?.

Short name Classes/AbstractStatic
Themes Analyze

9.10. Access Protected Structures

It is not allowed to access protected properties or methods from outside the class or its relatives.

<?php

class foo {
    protected $bar = 1;
}

$foo = new Foo();
$foo->bar = 2;

?>
Short name Classes/AccessProtected
Themes Analyze

9.11. Accessing Private

List of calls to private properties/methods that will compile but yield some fatal error upon execution.

<?php

class a {
    private $a;
}

class b extends a {
    function c() {
        $this->a;
    }
}

?>
Short name Classes/AccessPrivate
Themes Analyze

9.12. Action Should Be In Controller

Action methods should be in a controller and public.

<?php

use Zend\Mvc\Controller\AbstractActionController;

class SomeController extends AbstractActionController
{
    // Good method
    public function indexAction()
    {
        doSomething();
    }

    // Bad method : protected
    // turn protected into public, or drop the Action suffix
    protected function protectedIndexAction()
    {
        doSomething();
    }

    // Bad method : private
    // turn private into public, or drop the Action suffix
    protected function privateIndexAction()
    {
        doSomething();
    }

}


?>
Short name ZendF/ActionInController
Themes ZendFramework

9.13. Adding Zero

Adding 0 is useless, as 0 is the neutral element for addition. In PHP, it triggers a cast to integer.

It is recommended to make the cast explicit with (int)

<?php

// Explicit cast
$a = (int) foo();

// Useless addition
$a = foo() + 0;
$a = 0 + foo();

// Also works with minus
$b = 0 - $c; // drop the 0, but keep the minus
$b = $c - 0; // drop the 0 and the minus

$a += 0;
$a -= 0;

?>

If it is used to type cast a value to integer, then casting (integer) is clearer.

Short name Structures/AddZero
Themes Analyze
ClearPHP no-useless-math
Examples Thelia, OpenEMR

9.14. Aliases Usage

PHP manual recommends to avoid function aliases.

Some functions have several names, and both may be used the same way. However, one of the names is the main name, and the others are aliases. Aliases may be removed or change or dropped in the future. Even if this is not forecast, it is good practice to use the main name, instead of the aliases.

<?php

// official way to count an array
$n = count($array);

// official way to count an array
$n = sizeof($array);

?>

Aliases are compiled in PHP, and do not provide any performances over the normal function.

Aliases are more likely to be removed later, but they have been around for a long time.

See documentation : List of function aliases.

Short name Functions/AliasesUsage
Themes Analyze
ClearPHP no-aliases

9.15. All Uppercase Variables

Usually, global variables are all in uppercase, so as to differentiate them easily. Though, this is not always the case, with examples like $argc, $argv or $http_response_header.

When using custom variables, try to use lowercase $variables, $camelCase, $sturdyCase or $snake_case.

<?php

// PHP super global, also identified by the initial _
$localVariable = $_POST;

// PHP globals
$localVariable = $GLOBALS['HTTPS'];

?>

Predefined Variables

Short name Variables/VariableUppercase
Themes Coding Conventions

9.16. Already Parents Interface

The same interface is implemented by a class and one of its children.

That way, the child doesn’t need to implement the interface, nor define its methods to be an instance of the interface.

<?php

interface i {
    function i();
}

class A implements i {
    function i() {
        return '__METHOD__;
    }
}

// This implements is useless.
class AB extends A implements i {
    // No definition for function i()
}

// Implements i is understated
class AB extends A {
    // redefinition of the i method
    function i() {
        return '__METHOD__.' ';
    }
}

$x = new AB;
var_dump($x 'instanceof i);
// true

$x = new AC;
var_dump($x 'instanceof i);
// true

?>
Short name Interfaces/AlreadyParentsInterface
Themes Analyze, Suggestions

9.17. Altering Foreach Without Reference

Foreach() loop that should use a reference.

When using a foreach loop that modifies the original source, it is recommended to use referenced variables, rather than access the original value with $source[$index].

Using references is then must faster, and easier to read.

<?php

// Using references in foreach
foreach($source as $key => &$value) {
    $value = newValue($value, $key);
}

// Avoid foreach : use array_map
$source = array_walk($source, 'newValue');
    // Here, $key MUST be the second argument or newValue

// Slow version to update the array
foreach($source as $key => &$value) {
    $source[$key] = newValue($value, $key);
}
?>

You may also use ‘array_walk() or ‘array_map() (when $key is not used) to avoid the use of foreach.

See also Foreach.

Short name Structures/AlteringForeachWithoutReference
Themes Analyze
ClearPHP use-reference-to-alter-in-foreach

9.18. Alternative Syntax Consistence

PHP allows for two syntax : the alternative syntax, and the classic syntax.

The classic syntax is almost always used. When used, the alternative syntax is used in templates.

This analysis reports files that are using both syntax at the same time. This is confusing.

<?php

// Mixing both syntax is confusing.
foreach($array as $item) :
    if ($item > 1) {
        print $item elements\n;
    } else {
        print $item element\n;
    }
endforeach;

?>
Short name Structures/AlternativeConsistenceByFile
Themes Analyze

9.19. Always Anchor Regex

Unanchored regex finds the requested pattern, and leaves room for malicious content.

Without ^ and $, the regex is searches for any pattern that satisfies its criteria, leaving any unused part of the string available for abitrary content. It is recommended to use both anchor

<?php

$birthday = getSomeDate($_GET);

// Permissive version : $birthday = '1970-01-01<script>xss();</script>';
if (!preg_match('/\d{4}-\d{2}-\d{2}/', $birthday) {
    error('Wrong data format for your birthday!');
}

// Restrictive version : $birthday = '1970-01-01';
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $birthday) {
    error('Wrong data format for your birthday!');
}

echo 'Your birthday is on '.$birthday;

?>

Note that $ may be a line ending, still leaving room after it for injection.

<?php

$birthday = '1970-01-01'.PHP_EOL.'<script>xss();</script>';

?>

This analysis reports false positive when the regex is used to search a pattern in a much larger string. Check if this rule doesn’t apply, though.

See also CWE-625: Permissive Regular Expression.

Short name Security/AnchorRegex
Themes Security

9.20. Always Positive Comparison

Some PHP native functions, such as ‘count(), strlen(), or ‘abs() only returns positive or null values.

When comparing them to 0, the following expressions are always true and should be avoided.

<?php

$a = [1, 2, 3];

var_dump(count($a) >= 0);
var_dump(count($a) < 0);

?>
Short name Structures/NeverNegative
Themes Analyze

9.21. Ambiguous Array Index

Those indexes are defined with different types, in the same array.

Array indices only accept integers and strings, so any other type of literal is reported.

<?php

$x = [ 1  => 1,
      '1' => 2,
      1.0 => 3,
      true => 4];
// $x only contains one element : 1 => 4

// Still wrong, immediate typecast to 1
$x[1.0]  = 5;
$x[true] = 6;

?>

They are indeed distinct, but may lead to confusion.

Short name Arrays/AmbiguousKeys
Themes Analyze

9.22. Ambiguous Static

Methods or properties with the same name, are defined static in one class, and not static in another. This is error prone, as it requires a good knowledge of the code to make it static or not.

Try to keep the static-ness of methods simple, and unique. Consider renaming the methods and properties to distinguish them easily. A method and a static method have probably different responsabilities.

<?php

class a {
    function mixedStaticMethod() {}
}

class b {
    static function mixedStaticMethod() {}
}

/... a lot more code later .../

$c->mixedStaticMethod();
// or
$c::mixedStaticMethod();

?>
Short name Classes/AmbiguousStatic
Themes Analyze

9.23. Anonymous Classes

Anonymous classes.

<?php

// Anonymous class, available since PHP 7.0
$object = new class { function '__construct() { echo '__METHOD__; } };

?>
Short name Classes/Anonymous
Themes CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56

9.24. Argument Should Be Typehinted

When a method expects objects as argument, those arguments should be typehinted, so as to provide early warning that a wrong object is being sent to the method.

The analyzer will detect situations where a class, or the keywords ‘array’ or ‘callable’.

<?php

// What are the possible classes that have a 'foo' method?
function foo($bar) {
    return $bar->foo();
}

?>

‘Closure arguments are omitted.

Short name Functions/ShouldBeTypehinted
Themes Suggestions
ClearPHP always-typehint

9.25. Assign Default To Properties

Properties may be assigned default values at declaration time. Such values may be later modified, if needed.

<?php

class foo {
    private $propertyWithDefault = 1;
    private $propertyWithoutDefault;
    private $propertyThatCantHaveDefault;

    public function '__construct() {
        // Skip this extra line, and give the default value above
        $this->propertyWithoutDefault = 1;

        // Static expressions are available to set up simple computation at definition time.
        $this->propertyWithoutDefault = OtherClass::CONSTANT + 1;

        // Arrays, just like scalars, may be set at definition time
        $this->propertyWithoutDefault = [1,2,3];

        // Objects or resources can't be made default. That is OK.
        $this->propertyThatCantHaveDefault = fopen('/path/to/file.txt');
        $this->propertyThatCantHaveDefault = new Fileinfo();
    }
}

?>

Default values will save some instructions in the constructor, and makes the value obvious in the code.

Short name Classes/MakeDefault
Themes Analyze
ClearPHP use-properties-default-values

9.26. Assign With And

The lettered logical operators yield to assignation. It may collect less information than expected.

It is recommended to use the &&, ^ and || operators, instead of and, or and xor, to prevent confusion.

<?php

// The expected behavior is
// The following are equivalent
 $a =  $b  && $c;
 $a = ($b && $c);

// The unexpected behavior is
// The following are equivalent
 $a = $b  and $c;
($a = $b) and $c;

?>

See also Operator precedence.

Short name Php/AssignAnd
Themes Analyze
Examples xataface

9.27. Assigned Twice

The same variable is assigned twice in the same function.

While this is possible and quite common, it is also a good practice to avoid changing a value from one literal to another. It is far better to assign the new value to

Incremental changes to a variables are not reported here.

<?php

function foo() {
    // incremental changes of $a;
    $a = 'a';
    $a++;
    $a = uppercase($a);

    $b = 1;
    $c = bar($b);
    // B changed its purpose. Why not call it $d?
    $b = array(1,2,3);

    // This is some forgotten debug
    $e = $config->getSomeList();
    $e = array('OneElement');
}

?>
Short name Variables/AssignedTwiceOrMore
Themes Analyze

9.28. Avoid Concat In Loop

Concatenations inside a loop generate a lot of temporary variables. They are accumulated and tend to raise the memory usage, leading to slower performances.

It is recommended to store the values in an array, and then use ‘implode() on that array to make the concatenation at once. The effect is positive when the source array has at least 50 elements.

<?php

// Concatenation in one operation
$tmp = array();
foreach(data_source() as $data) {
    $tmp[] = $data;
}
$final = implode('', $tmp);

// Concatenation in many operations
foreach(data_source() as $data) {
    $final .= $data;
}

?>

The same doesn’t apply to addition and multiplication, with ‘array_sum() and array_multiply(), as those operations work on the current memory allocation, and don’t need to allocate new memory at each step.

Short name Performances/NoConcatInLoop
Themes Performances

9.29. Avoid Double Prepare

Double prepare shoud be avoided, for security reasons.

When preparing in two phases, any placeholder from the first part may be escaped by the second prepare, leading to their neutralization. This way, injecting ‘ %s ‘, leads to creating %s outside quotes : ‘ ‘ %s ‘ ‘ (external quotes are from the first prepare, while the internal set of quotes are from the second).

It is recommended to build the query and to prepare it in one call, to avoid such pitfall.

<?php

// Only one prepare
    $args = [$u, $t];
    $res = $wpdb->prepare(' select * from table user = %s and type = %s', $args);

// also only one prepare
    $args = [$u];
    $query = 'select * from table user = %s and type = %s';
    if ( $condition) {
        $query .= ' and type = %s';
        $args[] = $t;
    }
    $res = $wpdb->prepare($query, $args);

// double prepare
    $where = $wpdb->prepare('where user = %s', $s);
    $res = $wpdb->prepare(' select * from table $where AND other = %d', );

?>

See also On WordPress Security and Contributing and Disclosure: WordPress WPDB SQL Injection - Technical.

Short name Wordpress/DoublePrepare
Themes Wordpress

9.30. Avoid Large Array Assignation

Avoid setting large arrays to local variables. This is done every time the function is called.

There are different ways to avoid this : inject the array, build the array once. Using an constant or even a global variable is faster.

The effect on small arrays (less than 10 elements) is not significant. Arrays with 10 elements or more are reported here. The effect is also more important on functions that are called often, or within loops.

<?php

// with constants, for functions
const ARRAY = array(1,2,3,4,5,6,7,8,9,10,11);
function foo() {
    $array = ARRAY;
    //more code
}

// with class constants, for methods
class x {
    const ARRAY = array(1,2,3,4,5,6,7,8,9,10,11);
    function foo() {
        $array = self::ARRAY;
        //more code
    }
}

// with properties, for methods
class x {
    private $array = array(1,2,3,4,5,6,7,8,9,10,11);

    function foo() {
        $array = $this->array;
        //more code
    }
}

// injection, leveraging default values
function foo($array = array(1,2,3,4,5,6,7,8,9,10,11)) {
    //more code
}

// local cache with static
function foo() {
    static $array;
    if ($array === null) {
        $array = array(1,2,3,4,5,6,7,8,9,10,11);
    }

    //more code
}

// Avoid creating the same array all the time in a function
class x {
    function foo() {
        // assign to non local variable is OK.
        // Here, to a property, though it may be better in a '__construct or as default values
        $this->s = array(1,2,3,4,5,6,7,8,9,10,11);

        // This is wasting resources, as it is done each time.
        $array = array(1,2,3,4,5,6,7,8,9,10,11);
    }
}

?>
Short name Structures/NoAssignationInFunction
Themes Performances

9.31. Avoid Non Wordpress Globals

Refren using any global variable that is not Wordpress’s own.

Global variables are available for write and read across the whole application, making their data both easily accessible, and difficult to track when a unexpected change happen. It is recommended to rely on a mix of arguments passing and classes structures to reduce the code of any variable to a smaller part of the code.

<?php

my_hook() {
    // This is a Wordpress global
    $GLOBALS['is_safari'] = true;

    // is_iphone7 is not a Wordpress variable
    global $is_iphone7;
}

?>

See also Global Variables

Short name Wordpress/AvoidOtherGlobals
Themes Wordpress

9.32. Avoid Optional Properties

Avoid optional properties, to prevent litering the code with existence checks.

When a property has to be checked once for existence, it is safer to check it each time. This leads to a decrease in readability.

Either make sure the property is set with an actual object rather than with null, or use a void object. A void object offers the same interface than the expected object, but does nothing. It allows calling its methods, without running into a Fatal error, nor testing it.

<?php

// Example is courtesy 'The Coding Machine' : it has been adapted from its original form. See link below.

class MyMailer {
    private $logger;

    public function '__construct(LoggerInterface $logger = null) {
        $this->logger = $logger;
    }

    private function sendMail(Mail $mail) {
        // Since $this->logger may be null, it must be tested anytime it is used.
        if ($this->logger) {
            $this->logger->info('Mail successfully sent.');
        }
    }
}

?>

See also Avoid optional services as much as possible, The Null Object Pattern – Polymorphism in Domain Models, and Practical PHP Refactoring: Introduce Null Object.

Short name Classes/AvoidOptionalProperties
Themes Analyze

9.33. Avoid PHP Superglobals

Avoid using PHP superglobal when using Zend Framework. Zend Framework provides other ways to reach the incoming values : they should be used.

<?php

// Normal PHP code
$parameter = $_GET['parameter'];

// The Zend Framework way.
//
<?php
namespace <module name>\Controller;

use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;

class HelloController extends AbstractActionController
{
    public function worldAction()
    {
        $message = $this->params()->fromQuery('message', 'foo');
        return new ViewModel(['message' => $message]);
    }
}
?>

See also Quick Start of the Zend-mvc component.

Short name ZendF/DontUseGPC
Themes ZendFramework

9.34. Avoid Parenthesis

Avoid Parenthesis for language construct. Languages constructs are a few PHP native elements, that looks like functions but are not.

Among other distinction, those elements cannot be directly used as variable function call, and they may be used with or without parenthesis.

<?php

// normal usage of include
include 'file.php';

// This looks like a function and is not
include('file2.php');

?>

The usage of parenthesis actually give some feeling of comfort, it won’t prevent PHP from combining those argument with any later operators, leading to unexpected results.

Even if most of the time, usage of parenthesis is legit, it is recommended to avoid them.

Short name Structures/PrintWithoutParenthesis
Themes Analyze

9.35. Avoid Those Hash Functions

The following cryptographic algorithms are considered unsecure, and should be replaced with new and more performant algorithms.

MD2, MD4, MD5, SHA0, SHA1, CRC, DES, 3DES, RC2, RC4.

When possible, avoid using them, may it be as PHP functions, or hashing function configurations (mcrypt, hash…).

<?php

// Weak cryptographic algorithm
echo md5('The quick brown fox jumped over the lazy dog.');

// Weak crypotgraphic algorthim, used with a modern PHP extension (easier to update)
echo hash('md5', 'The quick brown fox jumped over the lazy dog.');

// Strong crypotgraphic algorthim, used with a modern PHP extension
echo hash('sha156', 'The quick brown fox jumped over the lazy dog.');

?>

Weak crypto are commonly used for hashing values when caching them. In such cases, security is not a primary concern. However, it may later become such, when hackers get access to the cache folders, or if the cached identifier is published. As a preventive protection, it is recommended to always use a secure hashing function.

See also Secure Hash Algorithms.

Short name Security/AvoidThoseCrypto
Themes Security

9.36. Avoid Using stdClass

stdClass is the default class for PHP. It is instantiated when PHP needs to return a object, but no class is specifically available.

It is recommended to avoid instantiating this class, nor use it is any way.

<?php

$json = '{a:1,b:2,c:3}';
$object = json_decode($json);
// $object is a stdClass, as returned by json_decode

// Fast building of $o
$a = [];
$a['a'] = 1;
$a['b'] = 2;
$a['c'] = 3;
json_encode( (object) $a);

// Slow building of $o
$o = new stdClass();
$o->a = 1;
$o->b = 2;
$o->c = 3;
json_encode($o);

?>

If you need a stdClass object, it is faster to build it as an array, then cast it, than instantiate stdClass. This is a micro-optimisation.

Short name Php/UseStdclass
Themes Analyze

9.37. Avoid array_push()

‘array_push() is slower than the [] operator.

This is also true if the [] operator is called several times, while ‘array_push() may be called only once. And using count after the push is also faster than collecting ‘array_push() return value.

<?php

$a = [1,2,3];
// Fast version
$a[] = 4;

$a[] = 5;
$a[] = 6;
$a[] = 7;
$count = count($a);

// Slow version
array_push($a, 4);
$count = array_push($a, 5,6,7);

// Multiple version :
$a[] = 1;
$a[] = 2;
$a[] = 3;
array_push($a, 1, 2, 3);


?>

This is a micro-optimisation.

Short name Performances/AvoidArrayPush
Themes Performances

9.38. Avoid array_unique()

The native function ‘array_unique() is much slower than using other alternative, such as ‘array_count_values(), ‘array_flip()/’array_keys(), or even a ‘foreach() loops.

<?php

// using 'array_unique()
$uniques = array_unique($someValues);

// When values are strings or integers
$uniques = array_keys(array_count_values($someValues));
$uniques = array_flip(array_flip($someValues))

//even some loops are faster.
$uniques = [];
foreach($someValues as $s) {
    if (!in_array($uniques, $s)) {
        $uniques[] $s;
    }
}

?>
Short name Structures/NoArrayUnique
Themes Performances

9.39. Avoid get_class()

get_class() should be replaced with the instanceof operator to check the class of an object.

get_class() only compares the full namespace name of the object’s class, while instanceof actually resolves the name, using the local namespace and aliases.

<?php

    use Stdclass as baseClass;

    function foo($arg) {
        // Slow and prone to namespace errors
        if (get_class($arg) === 'Stdclass') {
            // doSomething()
        }
    }

    function bar($arg) {
        // Faster, and uses aliases.
        if ($arg 'instanceof baseClass) {
            // doSomething()
        }
    }
?>
See also get_class and
Type Operators <http://php.net/’instanceof <http://php.net/manual/en/language.operators.type.php>`_>`_.
Short name Structures/UseInstanceof
Themes none

9.40. Avoid glob() Usage

‘glob() and ‘scandir() sorts results by default. If you don’t need that sorting, save some time by requesting NOSORT with those functions.

Besides, whenever possible, use ‘scandir() instead of ‘glob().

<?php

// Scandir without sorting is the fastest.
scandir('docs/', SCANDIR_SORT_NONE);

// Scandir sorts files by default. Same as above, but with sorting
scandir('docs/');

// glob sorts files by default. Same as below, but no sorting
glob('docs/*', GLOB_NOSORT);

// glob sorts files by default. This is the slowest version
glob('docs/*');

?>

Using ‘opendir() and a while loop may be even faster.

This analysis skips ‘scandir() and ‘glob() if they are explicitely configured with flags (aka, sorting is explicitely needed).

Glob() accepts wildchar, that may not easily replaced with ‘scandir() or ‘opendir().

See also Putting glob to the test.

Short name Performances/NoGlob
Themes Performances

9.41. Avoid set_error_handler $context Argument

Avoid configuring ‘set_error_handler() with a method that accepts 5 arguments. The last argument, $errcontext, is deprecated since PHP 7.2, and will be removed later.

<?php

// setting error_handler with an incorrect closure
set_error_handler(function($errno, $errstr, $errfile, $errline) {});

// setting error_handler with an incorrect closure
set_error_handler(function($errno, $errstr, $errfile, $errline, $errcontext) {});

?>

See also ‘set_error_handler();

Short name Php/AvoidSetErrorHandlerContextArg
Themes CompatibilityPHP72

9.42. Avoid sleep()/usleep()

‘sleep() and ‘usleep() help saturate the web server.

Pausing the script for a specific amount of time means that the Web server is also making all related ressources sleep, such as database, sockets, session, etc. This may used to set up a DOS on the server.

<?php

$begin = microtime(true);
checkLogin($user, $password);
$end   = microtime(true);

// Making all login checks looks the same
usleep(1000000 - ($end - $begin) * 1000000);

// Any hit on this page now uses 1 second, no matter if load is high or not
// Is it now possible to saturate the webserver in 1 s ?

?>

As much as possible, avoid delaying the end of the script.

‘sleep() and ‘usleep() have less impact in commandline (CLI).

Short name Security/NoSleep
Themes Security

9.43. Bail Out Early

When using conditions, it is recommended to quit in the current context, and avoid else clause altogether.

The main benefit is to make clear the method applies a condition, and stop quickly went it is not satisfied. The main sequence is then focused on the useful code.

This works with the ‘break, ‘continue, throw and goto keywords too, depending on situations.

<?php

// Bailing out early, low level of indentation
function foo1($a) {
    if ($a > 0) {
        return false;
    }

    $a++;
    return $a;
}

// Works with 'continue too
foreach($array as $a => $b) {
    if ($a > 0) {
        'continue false;
    }

    $a++;
    return $a;
}

// No need for else
function foo2($a) {
    if ($a > 0) {
        return false;
    } else {
        $a++;
    }

    return $a;
}

// No need for else : return goes into then.
function foo3($a) {
    if ($a < 0) {
        $a++;
    } else {
        return false;
    }

    return $a;
}

?>
Short name Structures/BailOutEarly
Themes Analyze

9.44. Binary Glossary

List of all the integer values using the binary format.

<?php

$a = 0b10;
$b = 0B0101;

?>
Short name Type/Binary
Themes CompatibilityPHP53

9.45. Bracketless Blocks

PHP allows one liners as ‘for(), ‘foreach(), ‘while(), do/’while() loops, or as then/else expressions.

It is generally considered a bad practice, as readability is lower and there are non-negligible risk of excluding from the loop the next instruction.

<?php

// Legit one liner
foreach(range('a', 'z') as $letter) ++$letterCount;

// More readable version, even for a one liner.
foreach(range('a', 'z') as $letter) {
    ++$letterCount;
}

?>

‘switch() cannot be without bracket.

Short name Structures/Bracketless
Themes Coding Conventions

9.46. Break Outside Loop

Starting with PHP 7, ‘break or ‘continue that are outside a loop (for, ‘foreach(), do…`’while() <http://php.net/manual/en/control-structures.while.php>`_, ‘while()) or a ‘switch() statement won’t compile anymore.

It is not possible anymore to include a piece of code inside a loop that will then ‘break.

<?php

    // outside a loop : This won't compile
    'break 1;

    foreach($array as $a) {
        'break 1; // Compile OK

        'break 2; // This won't compile, as this 'break is in one loop, and not 2
    }

    foreach($array as $a) {
        foreach($array2 as $a2) {
            'break 2; // OK in PHP 5 and 7
        }
    }
?>
Short name Structures/BreakOutsideLoop
Themes Analyze, CompatibilityPHP70

9.47. Break With 0

Cannot ‘break 0, as this makes no sense. Break 1 is the minimum, and is the default value.

<?php
    // Can't 'break 0. Must be 1 or more, depending on the level of nesting.
    for($i = 0; $i < 10; $i++) {
        'break 0;
    }

    for($i = 0; $i < 10; $i++) {
        for($j = 0; $j < 10; $j++) {
            'break 2;
        }
    }

?>
Short name Structures/Break0
Themes CompatibilityPHP53

9.48. Break With Non Integer

When using a ‘break, the argument of the operator must be a positive non-null integer literal or be omitted.

Other values were acceptable in PHP 5.3 and previous version, but this is now reported as an error.

<?php
    // Can't 'break $a, even if it contains an integer.
    $a = 1;
    for($i = 0; $i < 10; $i++) {
        'break $a;
    }

    // can't 'break on float
    for($i = 0; $i < 10; $i++) {
        for($j = 0; $j < 10; $j++) {
            'break 2.2;
        }
    }

?>
Short name Structures/BreakNonInteger
Themes CompatibilityPHP54

9.49. Buried Assignation

Those assignations are buried in the code, and placed in unexpected situations.

They are difficult to spot, and may be confusing. It is advised to place them in a more visible place.

<?php

// $b may be assigned before processing $a
$a = $c && ($b = 2);

// legit syntax, but the double assignation is not obvious.
for($i = 2, $j = 3; $j < 10; $j++) {

}
?>
Short name Structures/BuriedAssignation
Themes Analyze
Examples XOOPS, Mautic

9.50. CakePHP 2.5.0 Undefined Classes

CakePHP classes, interfaces and traits that are not defined in version 2.5.0.

Short name Cakephp/Cakephp25
Themes Cakephp

9.51. CakePHP 2.6.0 Undefined Classes

CakePHP classes, interfaces and traits that are not defined in version 2.6.0. 5 new classes

Short name Cakephp/Cakephp26
Themes Cakephp

9.52. CakePHP 2.7.0 Undefined Classes

CakePHP classes, interfaces and traits that are not defined in version 2.7.0. 12 new classes

2 removed classes

Short name Cakephp/Cakephp27
Themes Cakephp

9.53. CakePHP 2.8.0 Undefined Classes

CakePHP classes, interfaces and traits that are not defined in version 2.8.0. 8 new classes

Short name Cakephp/Cakephp28
Themes Cakephp

9.54. CakePHP 2.9.0 Undefined Classes

CakePHP classes, interfaces and traits that are not defined in version 2.9.0. 16 new classes

2 removed classes

Short name Cakephp/Cakephp29
Themes Cakephp

9.55. CakePHP 3.0 Deprecated Class

According to the Cake 3.0 migration guide, the following class is deprecated and should be removed.

  • Set (CakeUtilitySet) : replace it with Hash (CakeUtilityHash)
Short name Cakephp/Cake30DeprecatedClass
Themes Cakephp

9.56. CakePHP 3.0.0 Undefined Classes

CakePHP classes, interfaces and traits that are not defined in version 3.0.0. 754 new classes 13 new interfaces 34 new traits

1062 removed classes 7 removed interfaces

Short name Cakephp/Cakephp30
Themes Cakephp

9.57. CakePHP 3.1.0 Undefined Classes

CakePHP classes, interfaces and traits that are not defined in version 3.1.0. 64 new classes 5 new interfaces 5 new traits

16 removed classes

Short name Cakephp/Cakephp31
Themes Cakephp

9.58. CakePHP 3.2.0 Undefined Classes

CakePHP classes, interfaces and traits that are not defined in version 3.2.0. 27 new classes 4 new interfaces 4 new traits

1 removed classe

Short name Cakephp/Cakephp32
Themes Cakephp

9.59. CakePHP 3.3 Deprecated Class

According to the Cake 3.3 migration guide, the following class is deprecated and should be removed.

  • Mcrypt (CakeUtilityCryptoMcrypt) : replace it with CakeUtilityCryptoOpenssl or ext/openssl
Short name Cakephp/Cake33DeprecatedClass
Themes Cakephp

9.60. CakePHP 3.3.0 Undefined Classes

CakePHP classes, interfaces and traits that are not defined in version 3.3.0. 93 new classes 5 new interfaces 1 new trait

19 removed classes 1 removed interface

Short name Cakephp/Cakephp33
Themes Cakephp

9.61. CakePHP 3.4.0 Undefined Classes

CakePHP classes, interfaces and traits that are not defined in version 3.4.0. 41 new classes 1 new interface 1 new trait

16 removed classes 2 removed traits

Short name Cakephp/Cakephp34
Themes Cakephp

9.62. CakePHP Used

CakePHP classes, interfaces and traits being used in the code.

<?php

namespace App\Controller;

use Cake\Controller\Controller;

class AppController extends Controller
{

    public function initialize()
    {
        // Always enable the CSRF component.
        $this->loadComponent('Csrf');
    }

}

?>

See also CakePHP.

Short name Cakephp/CakePHPUsed
Themes Cakephp

9.63. Callback Needs Return

When used with array_map functions, the callback must return something.

<?php

// This filters each element
$filtered = array_filter($array, function ($x) {return $x == 2; });

// This return void for every element
$filtered = array_filter($array, function ($x) {return ; });

?>
Short name Functions/CallbackNeedsReturn
Themes Analyze

9.64. Calltime Pass By Reference

PHP doesn’t allow when a value is turned into a reference at functioncall, since PHP 5.4.

Either the function use a reference in its signature, either the reference won’t pass.

<?php

function foo($name) {
    $arg = ucfirst(strtolower($name));
    echo 'Hello '.$arg;
}

$a = 'name';
foo(&$a);

?>
Short name Structures/CalltimePassByReference
Themes CompatibilityPHP54

9.65. Can’t Count Non-Countable

Count() emits an error when it tries to count scalars or objects what don’t implement Countable interface.

<?php

// Normal usage
$a = array(1,2,3,4);
echo count($a).items\n;

// Error emiting usage
$a = '1234';
echo count($a).chars\n;

// Error emiting usage
echo count($unsetVar).elements\n;

?>

See also Warn when counting non-countable types.

Short name Structures/CanCountNonCountable
Themes CompatibilityPHP72

9.66. Can’t Extend Final

It is not possible to extend final classes.

Since PHP fails with a fatal error, this means that the extending class is probably not used in the rest of the code. Check for dead code.

<?php
    // File Foo
    final class foo {
        public final function bar() {
            // doSomething
        }
    }
?>

In a separate file :

<?php
    // File Bar
    class bar extends foo {

    }
?>
Short name Classes/CantExtendFinal
Themes Analyze, Dead code

9.67. Cant Inherit Abstract Method

Inheriting abstract methods was made available in PHP 7.2. In previous versions, it emits a Fatal error.

<?php

abstract class A           { abstract function bar(stdClass $x);  }
abstract class B extends A { abstract function bar($x): stdClass; }

//   Fatal error: Can't inherit abstract function A::bar()
?>

See also PHP RFC: Allow abstract function override.

Short name Classes/CantInheritAbstractMethod
Themes CompatibilityPHP53, CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56

9.68. Cant Instantiate Class

When constructor is not public, it is not possible to instantiate such a class. Either this is a conception choice, or there are factories to handle that. Either way, it is not possible to call new on such class.

PHP reports an error similar to this one : ‘Call to private Y::’__construct() from invalid context’.

<?php

//This is the way to go
$x = X::factory();

//This is not possible
$x = new X();

class X {
    //This is also the case with proctected '__construct
    private function '__construct() {}

    static public function factory() {
        return new X();
    }
}

?>
See also In a PHP5 class, when does a private constructor get called?,
Named Constructors in PHP and PHP Constructor Best Practices And The Prototype Pattern.
Short name Classes/CantInstantiateClass
Themes Analyze

9.69. Cant Use Return Value In Write Context

Empty() used to work only on data containers, such as variables. Until PHP 5.5, it was not possible to use directly expressions, such as functioncalls, inside an ‘empty() function call : they were met with a ‘Can’t use function return value in write context’ fatal error.

<?php

function foo($boolean) {
    return $boolean;
}

// Valid since PHP 5.5
echo empty(foo(true)) : 'true' : 'false';

?>

This also applies to methodcalls, static or not.

See also Cant Use Return Value In Write Context.

Short name Php/CantUseReturnValueInWriteContext
Themes CompatibilityPHP53, CompatibilityPHP54

9.70. Cast To Boolean

This expression may be reduced by casting to boolean type.

<?php

$variable = $condition == 'met' ? 1 : 0;
// Same as
$variable = (bool) $condition == 'met';

$variable = $condition == 'met' ? 0 : 1;
// Same as (Note the condition inversion)
$variable = (bool) $condition != 'met';
// also, with an indentical condition
$variable = !(bool) $condition == 'met';

// This also works with straight booleans expressions
$variable = $condition == 'met' ? true : false;
// Same as
$variable = $condition == 'met';

?>
Short name Structures/CastToBoolean
Themes Analyze
Examples MediaWiki, Dolibarr

9.71. Catch Overwrite Variable

The try/catch structure uses some variables that also in use in this scope. In case of a caught exception, the exception will be put in the catch variable, and overwrite the current value, loosing some data.

<?php

// variables and caught exceptions are distinct
$argument = 1;
try {
    methodThatMayRaiseException($argument);
} (Exception $e) {
    // here, $e has been changed to an exception.
}

// variables and caught exceptions are overlapping
$e = 1;
try {
    methodThatMayRaiseException();
} (Exception $e) {
    // here, $e has been changed to an exception.
}

?>

It is recommended to use another name for these catch variables.

Short name Structures/CatchShadowsVariable
Themes Analyze
ClearPHP no-catch-overwrite

9.72. Check All Types

When checking for time, avoid using else. Mention explicitly all tested type, and raise an exception when reaching else.

PHP has a short list of scalar types : null, boolean, integer, real, strings, object, resource and array. When a variable is not holding one the the type, then it may be of any other type.

Most of the time, when using a simple ‘is_string() / else test, this is relying on the conception of the code. By construction, the arguments may be one of two types : array or string.

What happens often is that in case of failure in the code (database not working, another class not checking its results), a third type is pushed to the structure, and it ends up breaking the execution.

The safe way is to check the various types all the time, and use the default case (here, the else) to throw exception() or test an assertion and handle the special case.

<?php

// hasty version
if (is_array($argument)) {
    $out = $argument;
} else {
    // Here, $argument is NOT an array. What if it is an object ? or a NULL ?
    $out = array($argument);
}

// Safe type checking : do not assume that 'not an array' means that it is the other expected type.
if (is_array($argument)) {
    $out = $argument;
} elseif (is_string($argument)) {
    $out = array($argument);
} else {
    assert(false, '$argument is not an array nor a string, as expected!');
}

?>

Using ‘is_callable(), is_iterable() with this structure is fine : when variable is callable or not, while a variable is an integer or else.

Using a type test without else is also accepted here. This is a special treatment for this test, and all others are ignored. This aspect may vary depending on situations and projects.

Short name Structures/CheckAllTypes
Themes Analyze

9.73. Child Class Removes Typehint

PHP 7.2 introduced the ability to remove a typehint when overloarding a method. This is not valid code for older versions.

<?php

class foo {
    function foobar(foo $a) {}
}

class bar extends foo {
    function foobar($a) {}
}

?>
Short name Classes/ChildRemoveTypehint
Themes CompatibilityPHP53, CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56

9.74. Class Const With Array

Constant defined with const keyword may be arrays but only stating with PHP 5.6. Define never accept arrays : it only accepts scalar values.

Short name Php/ClassConstWithArray
Themes CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55

9.75. Class Function Confusion

Avoid classes and functions bearing the same name.

When functions and classes bear the same name, calling them may be confusing. This may also lead to forgotten ‘new’ keyword.

<?php

class foo {}

function foo() {}

// Forgetting the 'new' operator is easy
$object = new foo();
$object = foo();

?>
Short name Php/ClassFunctionConfusion
Themes Analyze

9.76. Class Name Case Difference

The spotted classes are used with a different case than their definition. While PHP accepts this, it makes the code harder to read.

It may also be a violation of coding conventions.

<?php

// This use statement has wrong case for origin.
use Foo as X;

// Definition of the class
class foo {}

// Those instantiations have wrong case
new FOO();
new X();

?>

See also PHP class name constant case sensitivity and PSR-11.

Short name Classes/WrongCase
Themes Coding Conventions, Analyze

9.77. Class Should Be Final By Ocramius

‘Make your classes always final, if they implement an interface, and no other public methods are defined’.

When a class should be final, as explained by Ocramiux (Marco Pivetta).

Full article : When to declare classes final.

<?php

interface i1 {
    function i1() ;
}

// Class should final, as its public methods are in an interface
class finalClass implements i1 {
    // public interface
    function i1 () {}

    // private method
    private function a1 () {}
}

?>
Short name Classes/FinalByOcramius
Themes Analyze

9.78. Class, Interface Or Trait With Identical Names

The following names are used at the same time for classes, interfaces or traits. For example,

<?php
    class a { /* some definitions */ }
    interface a { /* some definitions */ }
    trait a { /* some definitions */ }
?>

Even if they are in different namespaces, this makes them easy to confuse. Besides, it is recommended to have markers to differentiate classes from interfaces from traits.

Short name Classes/CitSameName
Themes Analyze

9.79. Classes Mutually Extending Each Other

Those classes are extending each other, creating an extension loop. PHP will yield a fatal error at running time, even if it is compiling the code.

<?php

// This code is lintable but won't run
class Foo extends Bar { }
class Bar extends Foo { }

// The loop may be quite large
class Foo extends Bar { }
class Bar extends Bar2 { }
class Bar2 extends Foo { }

?>
Short name Classes/MutualExtension
Themes Analyze

9.80. Close Tags

PHP manual recommends that script should be left open, without the final closing ?>. This way, one will avoid the infamous bug ‘Header already sent’, associated with left-over spaces, that are lying after this closing tag.

Short name Php/CloseTags
Themes Coding Conventions
ClearPHP leave-last-closing-out

9.81. Closure May Use $this

When closure were introduced in PHP, they couldn’t use the $this variable, making is cumbersome to access local properties when the closure was created within an object.

<?php

// Invalid code in PHP 5.4 and less
class Test
{
    public function testing()
    {
        return function() {
            var_dump($this);
        };
    }
}

$object = new Test;
$function = $object->testing();
$function();

?>

This is not the case anymore since PHP 5.4.

See also Anonymus Functions.

Short name Php/ClosureThisSupport
Themes CompatibilityPHP53

9.82. Common Alternatives

In the following conditional structures, expressions were found that are common to both ‘then’ and ‘else’. It may be interesting, though not always possible, to put them both out of the conditional, and reduce line count.

<?php
if ($c == 5) {
    $b = strtolower($b[2]);
    $a++;
} else {
    $b = strtolower($b[2]);
    $b++;
}
?>

may be rewritten in :

<?php

$b = strtolower($b[2]);
if ($c == 5) {
    $a++;
} else {
    $b++;
}

?>
Short name Structures/CommonAlternatives
Themes Analyze

9.83. Compare Hash

When comparing hash values, it is important to use the strict comparison : === or !==.

In a number of situations, the hash value will start with ‘0e’, and PHP will understand that the comparison involves integers : it will then convert the strings into numbers, and it may end up converting them to 0.

Here is an example

<?php

// The two following passwords hashes matches, while they are not the same.
$hashed_password = 0e462097431906509000000000000;
if (hash('md5','240610708',false) == $hashed_password) {
  print 'Matched.'.PHP_EOL;
}

// hash returns a string, that is mistaken with 0 by PHP
// The strength of the hashing algorithm is not a problem
if (hash('ripemd160','20583002034',false) == '0') {
  print 'Matched.'.PHP_EOL;
}

if (hash('md5','240610708',false) !== $hashed_password) {
  print 'NOT Matched.'.PHP_EOL;
}

// Display true
var_dump(md5('240610708') == md5('QNKCDZO') );

?>

You may also use ‘password_hash() and ‘password_verify() : they work together without integer conversion problems, and they can’t be confused with a number.

See also Magic Hashes and
md5(‘240610708’) == md5(‘QNKCDZO’).
Short name Security/CompareHash
Themes Security
ClearPHP strict-comparisons
Examples Traq, LiveZilla

9.84. Compared Comparison

Usually, comparison are sufficient, and it is rare to have to compare the result of comparison. Check if this two-stage comparison is really needed.

<?php

if ($a === strpos($string, $needle) > 2) {}

// the expression above apply precedence :
// it is equivalent to :
if (($a === strpos($string, $needle)) > 2) {}

?>

See also Operators Precedence.

Short name Structures/ComparedComparison
Themes Analyze

9.85. Concrete Visibility

Methods that implements an interface in a class must be public.

PHP doesn’t lint this, unless the interface and the class are in the same file. At execution, it stops immediately with a Fatal error : ‘Access level to c::iPrivate() must be public (as in class i) ‘;

<?php

interface i {
    function iPrivate() ;
    function iProtected() ;
    function iPublic() ;
}

class c implements i {
    // Methods that implements an interface in a class must be public.
    private function iPrivate() {}
    protected function iProtected() {}
    public function iPublic() {}
}

?>

See also Interfaces.

Short name Interfaces/ConcreteVisibility
Themes Analyze

9.86. Configure Extract

The ‘extract() function overwrites local variables when left unconfigured.

Extract imports variables from an array into the local scope. In case of a conflict, that is when a local variable already exists, it overwrites the previous variable.

In fact, ‘extract() may be configured to handle the situation differently : it may skip the conflicting variable, prefix it, prefix it only if it exists, only import overwriting variables… It may also import them as references to the original values.

This analysis reports ‘extract() when it is not configured explicitely. If overwriting is the intended objective, it is not reported.

<?php

// ignore overwriting variables
extract($array, EXTR_SKIP);

// prefix all variables explicitely variables with 'php_'
extract($array, EXTR_PREFIX_ALL, 'php_');

// overwrites explicitely variables
extract($array, EXTR_OVERWRITE);

// overwrites implicitely variables : do we really want that?
extract($array, EXTR_OVERWRITE);

?>

Always avoid using ‘extract() on untrusted sources, such as $_GET, $_POST, $_FILES, or even databases records.

See also extract.

Short name Security/ConfigureExtract
Themes Security

9.87. Const With Array

The const keyword supports array. This feature was added in PHP 5.6.

The array must be filled with other constants. It may also be build using the ‘+’ operator.

<?php

const PRIMES = [2, 3, 5, 7];

class X {
    const TWENTY_THREE = 23;
    const MORE_PRIMES = PRIMES + [11, 13, 17, 19];
    const EVEN_MORE_PRIMES = self::MORE_PRIMES + [self::TWENTY_THREE];
}

?>
See also Class Constants and
Constants Syntax.
Short name Php/ConstWithArray
Themes CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55

9.88. Constant Class

A class or an interface only made up of constants. Constants usually have to be used in conjunction of some behavior (methods, class…) and never alone.

<?php

class ConstantClass {
    const KBIT = 1000;
    const MBIT = self::KBIT * 1000;
    const GBIT = self::MBIT * 1000;
    const PBIT = self::GBIT * 1000;
}

?>

As such, they should be PHP constants (build with define or const), or included in a class with other methods and properties.

See also PHP Classes containing only constants.

Short name Classes/ConstantClass
Themes Analyze

9.89. Constant Comparison

Constant to the left or right is a favorite.

Comparisons are commutative : they may be $a == B or B == $a. The analyzed code show less than 10% of one of the two : for consistency reasons, it is recommended to make them all the same.

Putting the constant on the left is also called ‘Yoda Comparison’, as it mimics the famous characters style of speech. It prevents errors like ‘B = $a’ where the comparison is turned into an assignation.

The natural way is to put the constant on the right. It is often less surprising.

Every comparison operator is used when finding the favorite.

<?php

//
if ($a === B) { doSomething(); }
if ($c > D) { doSomething(); }
if ($e !== G) { doSomething(); }
do { doSomething(); } while ($f === B);
while ($a === B) { doSomething(); }

// be consistent
if (B === $a) {}

// Compari
if (B <= $a) {}

?>
Short name Structures/ConstantComparisonConsistance
Themes Coding Conventions

9.90. Constant Scalar Expressions

Define constant with the result of static expressions. This means that constants may be defined with the const keyword, with the help of various operators but without any functioncalls.

This feature was introduced in PHP 5.6. It also supports array(), and expressions in arrays.

Those expressions (using simple operators) may only manipulate other constants, and all values must be known at compile time.

<?php

// simple definition
const A = 1;

// constant scalar expression
const B = A * 3;

// constant scalar expression
const C = [A '** 3, '3' => B];

?>

See also Constant Scalar Expressions.

Short name Structures/ConstantScalarExpression
Themes CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55

9.91. Constants Created Outside Its Namespace

Constants Created Outside Its Namespace.

Using the ‘define() function, it is possible to create constant outside their namespace, but using the fully qualified namespace.

<?php

namespace A\B {
    // define A\B\C as 1
    define('C', 1);
}

namespace D\E {
    // define A\B\C as 1, while outside the A\B namespace
    define('A\B\C', 1);
}

?>

However, this makes the code confusing and difficult to debug. It is recommended to move the constant definition to its namespace.

Short name Constants/CreatedOutsideItsNamespace
Themes Analyze

9.92. Constants With Strange Names

List of constants being defined with names that are incompatible with PHP standards.

<?php

// Define a valid PHP constant
define('ABC', 1);
const ABCD = 2;

// Define an invalid PHP constant
define('ABC!', 1);
echo defined('ABC!') ? constant('ABC!') : 'Undefined';

// Const doesn't allow illegal names

?>

See also PHP Constants.

Short name Constants/ConstantStrangeNames
Themes Analyze

9.93. Could Be Class Constant

When a property is defined and read, but never modified, it may be a constant.

<?php

class foo {
    // $this->bar is never modified.
    private $bar = 1;

    // $this->foofoo is modified, at least once
    private $foofoo = 2;

    function method($a) {
        $this->foofoo = $this->bar + $a + $this->foofoo;

        return $this->foofoo;
    }

}

?>

Starting with PHP 5.6, even array() may be defined as constants.

Short name Classes/CouldBeClassConstant
Themes Analyze

9.94. Could Be Else

Merge opposition conditions into one if/then structure.

When two if/then structures follow each other, using a condition and its opposite, they may be merged into one.

<?php

// Short version
if ($a == 1) {
    $b = 2;
} else {
    $b = 1;
}

// Long version
if ($a == 1) {
    $b = 2;
}

if ($a != 1) {
    $b = 3;
}

?>
Short name Structures/CouldBeElse
Themes Analyze

9.95. Could Be Private Class Constant

Class constant may use private visibility.

Since PHP 7.1, constants may also have a public/protected/private visibility. This restrict their usage to anywhere, class and children or class.

As a general rule, it is recommended to make constant private by default, and to relax this restriction as needed. PHP makes them public by default.

<?php

class foo {
    // pre-7.1 style
    const PRE_71_CONSTANT = 1;

    // post-7.1 style
    private const PRIVATE_CONSTANT = 2;
    public const PUBLIC_CONSTANT = 3;

    function bar() {
        // PRIVATE CONSTANT may only be used in its class
        echo self::PRIVATE_CONSTANT;
    }
}

// Other constants may be used anywhere
function x($a = foo::PUBLIC_CONSTANT) {
    echo $a.' '.foo:PRE_71_CONSTANT;
}

?>

Constant shall stay public when the code has to be compatible with PHP 7.0 and older.

They also have to be public in the case of component : some of those constants have to be used by external actors, in order to configure the component.

See also Class Constants.

Short name Classes/CouldBePrivateConstante
Themes Analyze
Examples Phinx

9.96. Could Be Protected Class Constant

Class constant may use ‘protected’ visibility.

Since PHP 7.1, constants may also have a public/protected/private visibility. This restrict their usage to anywhere, class and children or class.

As a general rule, it is recommended to make constant ‘private’ by default, and to relax this restriction as needed. PHP makes them public by default.

<?php

class foo {
    // pre-7.1 style
    const PRE_71_CONSTANT = 1;

    // post-7.1 style
    protected const PROTECTED_CONSTANT = 2;
    public const PUBLIC_CONSTANT = 3;
}

class foo2 extends foo {
    function bar() {
        // PROTECTED_CONSTANT may only be used in its class or its children
        echo self::PROTECTED_CONSTANT;
    }
}

class foo3 extends foo {
    function bar() {
        // PROTECTED_CONSTANT may only be used in its class or any of its children
        echo self::PROTECTED_CONSTANT;
    }
}

// Other constants may be used anywhere
function x($a = foo::PUBLIC_CONSTANT) {
    echo $a.' '.foo:PRE_71_CONSTANT;
}

?>
Short name Classes/CouldBeProtectedConstant
Themes Analyze

9.97. Could Be Protected Method

Those methods are declared public, but are never used publicly. They may be made protected.

<?php

class foo {
    // Public, and used publicly
    public publicMethod() {}

    // Public, but never used outside the class or its children
    public protectedMethod() {}

    private function bar() {
        $this->protectedMethod();
    }
}

$foo = new Foo();
$foo->publicMethod();

?>

These properties may even be made private.

Short name Classes/CouldBeProtectedMethod
Themes Analyze

9.98. Could Be Protected Property

Those properties are declared public, but are never used publicly. They may be made protected.

<?php

class foo {
    // Public, and used publicly
    public $publicProperty;
    // Public, but never used outside the class or its children
    public $protectedProperty;

    function bar() {
        $this->protectedProperty = 1;
    }
}

$foo = new Foo();
$foo->publicProperty = 3;

?>

This property may even be made private.

Short name Classes/CouldBeProtectedProperty
Themes Analyze

9.99. Could Be Static

This global is only used in one function or method. It may be called ‘static’, instead of global. This allows you to keep the value between call to the function, but will not be accessible outside this function.

<?php
function foo( ) {
    static $variableIsReservedForX; // only accessible within foo( ), even between calls.
    global $variableIsGlobal;       //      accessible everywhere in the application
}
?>
Short name Structures/CouldBeStatic
Themes Analyze
Examples Dolphin, Contao

9.100. Could Be Typehinted Callable

Those arguments may use the callable Typehint.

‘callable’ is a PHP keyword that represents callback functions. Those may be used in dynamic function call, like $function(); or as callback functions, like with ‘array_map();

callable may be a string representing a function name or a static call (including ::), an array with two elements, (a class or object, and a method), or a closure.

When arguments are used to call a function, but are not marked with ‘callable’, they are reported by this analysis.

<?php

function foo(callable $callable) {
    // very simple callback
    return $callable();
}

function foo2($array, $callable) {
    // very simple callback
    return array_map($array, $callable);
}

?>

See also Callback / callable.

Short name Functions/CouldBeCallable
Themes Analyze

9.101. Could Make A Function

When a function is called across the code with the same arguments often enough, it should be turned into a local API.

This approach is similar to turning literals into constants : it centralize the value, it helps refactoring by updating it. It also makes the code more readable. Moreover, it often highlight common grounds between remote code locations.

The analysis looks for functions calls, and checks the arguments. When the calls occurs more than 4 times, it is reported.

<?php

// str_replace is used to clean '&' from strings.
// It should be upgraded to a central function
function foo($arg ) {
    $arg = str_replace('&', '', $arg);
    // do something with $arg
}

class y {
    function bar($database ) {
        $value = $database->queryName();
        $value = str_replace('&', '', $value);
        // $value = removeAmpersand($value);
        // do something with $arg2
    }
}

// helper function
function removeAmpersand($string) {
    return str_replace('&', '', $string);
}

?>
Short name Functions/CouldCentralize
Themes Analyze, Suggestions

9.102. Could Return Void

The following functions may bear the Void return typeHint.

<?php

// This can be Void
function foo(&$a) {
    ++$a;
    return;
}

// This can't be Void
function bar($a) {
    ++$a;
    return $a;
}

?>
Short name Functions/CouldReturnVoid
Themes Suggestions

9.103. Could Typehint

Arguments that are tested with ‘instanceof gain from making it a Typehint.

<?php

function foo($a, $b) {
    // $a is tested for B with 'instanceof.
    if (!$a 'instanceof B) {
        return;
    }

    // More code
}

function foo(B $a, $b) {
    // May omit the initial test

    // More code
}

?>
Short name Functions/CouldTypehint
Themes Analyze

9.104. Could Use Alias

This long name may be reduced by using an available alias.

<?php

use a\b\c;

// This may be reduced with the above alias
new a\b\c\d();

// This too
new a\b\c\d\e\f();

// This yet again
new a\b\c();

?>
Short name Namespaces/CouldUseAlias
Themes Analyze

9.105. Could Use Compact

Compact() turns a group of variables into an array. It may be used to simplify expressions.

<?php

$a = 1;
$b = 2;

// Compact call
$array = compact('a', 'b');

$array === [1, 2];

// Detailing all the keys and their value
$array = ['a' => $a, 'b' => $b];

?>

Note that compact accepts any string, and any undefined variable is not set, without a warning.

See also compact.

Short name Structures/CouldUseCompact
Themes Suggestions

9.106. Could Use Short Assignation

Use short assignment operator, to speed up code, and keep syntax clear.

Some operators, like * or +, have a compact and fast ‘do-and-assign’ version. They looks like a compacted version for = and the operator. This syntax is good for readability, and saves some memory in the process.

Depending on the operator, not all permutations of arguments are possible.

Addition and short assignation of addition have a different set of features when applied to arrays. Do not exchange one another in that case.

<?php

$a = 10 + $a;
$a += 10;

$b = $b - 1;
$b -= 1;

$c = $c * 2;
$c *= 2;

$d = $d / 3;
$d /= 3;

$e = $e % 4;
$e %= 4;

$f = $f | 5;
$f |= 5;

$g = $g & 6;
$g &= 6;

$h = $h ^ 7;
$h ^= 7;

$i = $i >> 8;
$i >>= 8;

$j = $j << 9;
$j <<= 9;

?>

Short operators are faster than the extended version, though it is a micro-optimization.

See also Assignation Operators.

Short name Structures/CouldUseShortAssignation
Themes Analyze, Performances
ClearPHP use-short-assignations
Examples ChurchCRM, Thelia

9.107. Could Use __DIR__

Use ‘__DIR__ constant to access the current file’s parent directory.

Avoid using ‘dirname() on ‘__FILE__.

<?php

// Better way
$fp = fopen('__DIR__.'/myfile.txt', 'r');

// compatible, but slow way
$fp = fopen(dirname('__FILE__).'/myfile.txt', 'r');

// Since PHP 5.3
assert(dirname('__FILE__) == '__DIR__);

?>

‘__DIR__ has been introduced in PHP 5.3.0.

See also Magic Constants.

Short name Structures/CouldUseDir
Themes Analyze, Suggestions

9.108. Could Use array_fill_keys

‘array_fill_keys() is a native PHP function that creates an array from keys. It gets the list of keys, and a constant value to assign to each keys.

This is twice faster than doing the same with a loop.

<?php

$array = range('a', 'z');

// Fast way to build the array
$b = array_fill_key($a, 0);

// Slow way to build the array
foreach($array as $a) {
    $b[$a] = 0;
}

?>

See also array_fill_keys.

Short name Structures/CouldUseArrayFillKeys
Themes Suggestions

9.109. Could Use array_unique

Use array_unique to collect unique elements from an array.

Always try to use native PHP functions, instead of rebuilding them with custom PHP code.

<?php

    $unique = array();
    foreach ($array as $b) {
        if (!in_array($b, $unique)) {
            /*  May be more code */
            $unique[] = $b;
        }
    }
?>

See also array_unique.

Short name Structures/CouldUseArrayUnique
Themes Suggestions

9.110. Could Use self

self keyword refers to the current class, or any of its parents. Using it is just as fast as the full classname, it is as readable and it is will not be changed upon class or namespace change.

It is also routinely used in traits : there, self represents the class in which the trait is used, or the trait itself.

<?php

class x {
    const FOO = 1;

    public function bar() {
        return self::FOO;
// same as return x::FOO;
    }
}

?>

See also Scope Resolution Operator (::).

Short name Classes/ShouldUseSelf
Themes Analyze, Suggestions

9.111. Could Use str_repeat()

Use ‘str_repeat() or ‘str_pad() instead of making a loop.

Making a loop to repeat the same concatenation is actually much longer than using ‘str_repeat(). As soon as the loop repeats more than twice, ‘str_repeat() is much faster. With arrays of 30, the difference is significant, though the whole operation is short by itself.

<?php

// This adds 7 'e' to $x
$x .= str_repeat('e', 7);

// This is the same as above,
for($a = 3; $a < 10; ++$a) {
    $x .= 'e';
}

// here, $default must contains 7 elements to be equivalent to the previous code
foreach($default as $c) {
    $x .= 'e';
}

?>
Short name Structures/CouldUseStrrepeat
Themes Analyze

9.112. Crc32() Might Be Negative

‘crc32() may return a negative number, on 32bits platforms.

According to the manual : Because PHP’s integer type is signed many crc32 checksums will result in negative integers on 32bit platforms. On 64bit installations all ‘crc32() results will be positive integers though.

<?php

// display the checksum with %u, to make it unsigned
echo sprintf('%u', crc32($str));

// turn the checksum into an unsigned hexadecimal
echo dechex(crc32($str));

// avoid concatenating crc32 to a string, as it may be negative on 32bits platforms
echo 'prefix'.crc32($str);

?>

See also crc32().

Short name Php/Crc32MightBeNegative
Themes Analyze

9.113. Curly Arrays

It is possible to access individual elements in an array by using its offset between square brackets [] or curly brackets {}.

<?php

$array = ['a', 'b', 'c', 'd', 'e'];

print $array[2]; // displays 'b';
print $array{3}; // displays 'c';


?>

Curly brackets are seldom used, and will probably confuse or surprise the reader. It is recommended not to used them.

See also Array.

Short name Arrays/CurlyArrays
Themes Coding Conventions

9.114. Dangling Array References

Always unset a referenced-variable used in a loop.

It is highly recommended to unset blind variables when they are set up as references after a loop.

<?php

$array = array(1,2,3,4);

foreach($array as &$a) {
    $a += 1;
}
// This only unset the reference, not the value
unset($a);




// Dangling array problem
foreach($array as &$a) {
    $a += 1;
}
//$array === array(3,4,5,6);

// This does nothing (apparently)
// $a is already a reference, even if it doesn't show here.
foreach($array as $a) {}
//$array === array(3,4,5,5);

?>

When omitting this step, the next loop that will also require this variable will deal with garbage values, and produce unexpected results.

See also : No Dangling Reference,
PHP foreach pass-by-reference: Do it right, or better not at all, How does PHP ‘foreach’ actually work?, References and foreach.
Short name Structures/DanglingArrayReferences
Themes Analyze
ClearPHP no-dangling-reference
Examples Typo3, SugarCrm

9.115. Deep Definitions

Structures, such as functions, classes, interfaces, traits, etc. may be defined anywhere in the code, including inside functions. This is legit code for PHP.

Since the availability of __autoload, there is no need for that kind of code. Structures should be defined, and accessible to the autoloading. Inclusion and deep definitions should be avoided, as they compell code to load some definitions, while autoloading will only load them if needed.

<?php

class X {
    function init() {
        // myFunction is defined when and only if X::init() is called.
        if (!function_exists('myFunction'){
            function myFunction($a) {
                return $a + 1;
            }
        })
    }
}

?>

Functions are excluded from autoload, but shall be gathered in libraries, and not hidden inside other code.

Constants definitions are tolerated inside functions : they may be used for avoiding repeat, or noting the usage of such function.

See also Autoloading Classe.

Short name Functions/DeepDefinitions
Themes Analyze
Examples Dolphin

9.116. Define With Array

PHP 7.0 has the ability to define an array as a constant, using the ‘define() native call. This was not possible until that version, only with the const keyword.

<?php

//Defining an array as a constant
define('MY_PRIMES', [2, 3, 5, 7, 11]);

?>
Short name Php/DefineWithArray
Themes CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56

9.117. Defined View Property

View variables are set by calling the methods setVariable or setVariables on the View object.

<?php

$model    = new ViewModel();
// foo is set to bar
$model->setVariable('foo', 'bar');

?>
Short name ZendF/DefinedViewProperty
Themes ZendFramework

9.118. Dependant Trait

Traits should be autonomous. It is recommended to avoid depending on methods or properties that should be in the using class.

The following traits make usage of methods and properties, static or not, that are not defined in the trait. This means the host class must provide those methods and properties, but there is no way to enforce this.

This may also lead to dead code : when the trait is removed, the host class have unused properties and methods.

<?php

// autonomous trait : all it needs is within the trait
trait t {
    private $p = 0;

    function foo() {
        return ++$this->p;
    }
}

// dependant trait : the host class needs to provide some properties or methods
trait t2 {
    function foo() {
        return ++$this->p;
    }
}

class x {
    use t2;

    private $p = 0;
}
?>
Short name Traits/DependantTrait
Themes Analyze

9.119. Deprecated Functions

The following functions are deprecated. Whatever the version you are using, it is recommended to stop using them and replace them with a durable equivalent.

Functions may be still usable : they generate warning that help you track their usage. Watch your logs, and target any deprecated warning. This way, you won’t be stuck when the function is actually removed.

<?php

// This is the current function
list($day, $month, $year) = explode('/', '08/06/1995');

// This is deprecated
list($day, $month, $year) = split('/', '08/06/1995');

?>
Short name Php/Deprecated
Themes Analyze
ClearPHP no-deprecated

9.120. Deprecated Methodcalls in Cake 3.2

According to the Cake Migration Guide, the following are deprecated and should be changed.

  • Shell::error()
  • CakeDatabaseExpressionQueryExpression::type()
  • CakeORMResultSet::_calculateTypeMap()
  • CakeORMResultSet::_castValues()

See also Cake 3.2 migration guide.

Short name Cakephp/Cake32DeprecatedMethods
Themes Cakephp

9.121. Deprecated Methodcalls in Cake 3.3

According to the Cake 3.3 migration guide, the following are deprecated and should be changed.

  • Shell::error()
Short name Cakephp/Cake33DeprecatedMethods
Themes Cakephp

9.122. Deprecated Static calls in Cake 3.3

According to the Cake 3.3 migration guide, the following are deprecated and should be changed.

  • Router::mapResources() is deprecated. Use routing scopes and $routes->resources() instead.
  • Router::redirect() is deprecated. Use routing scopes and $routes->redirect() instead.
Short name Cakephp/Cake33DeprecatedStaticmethodcall
Themes Cakephp

9.123. Deprecated Trait in Cake 3.3

According to the Cake 3.3 migration guide, the following are deprecated and should be changed.

  • CakeRoutingRequestActionTrait
Short name Cakephp/Cake33DeprecatedTraits
Themes Cakephp

9.124. Dereferencing String And Arrays

PHP allows the direct dereferencing of strings and arrays.

This was added in PHP 5.5. There is no need anymore for an intermediate variable between a string and array (or any expression generating such value) and accessing an index.

<?php
$x = array(4,5,6);
$y = $x[2] ; // is 6

May be replaced by
$y = array(4,5,6)[2];
$y = [4,5,6][2];
?>
Short name Structures/DereferencingAS
Themes CompatibilityPHP53, CompatibilityPHP54

9.125. Direct Injection

The following code act directly upon PHP incoming variables like $_GET and $_POST. This make those snippet very unsafe.

<?php

// Direct injection
echo Hello.$_GET['user']., welcome.;

// less direct injection
foo($_GET['user']);
function foo($user) {
    echo Hello.$user., welcome.;
}

?>
Short name Security/DirectInjection
Themes Security

9.126. Do In Base

Use SQL expression to compute aggregates.

<?php

// Efficient way
$res = $db->query('SELECT sum(e) AS sumE FROM table WHERE condition');

// The sum is already done
$row = $res->fetchArray();
$c += $row['sumE'];

// Slow way
$res = $db->query('SELECT e FROM table WHERE condition');

// This aggregates the column e in a slow way
while($row = $res->fetchArray()) {
    $c += $row['e'];
}

?>
Short name Performances/DoInBase
Themes Performances

9.127. Don’t Change Incomings

PHP hands over a lot of information using special variables like $_GET, $_POST, etc… Modifying those variables and those values inside de variables means that the original content is lost, while it will still look like raw data, and, as such, will be untrustworthy.

<?php

// filtering and keeping the incoming value.
$_DATA'id'] = (int) $_GET['id'];

// filtering and changing the incoming value.
$_GET['id'] = strtolower($_GET['id']);

?>

It is recommended to put the modified values in another variable, and keep the original one intact.

Short name Structures/NoChangeIncomingVariables
Themes Analyze

9.128. Don’t Echo Error

It is recommended to avoid displaying error messages directly to the browser.

PHP’s uses the ‘display_errors’ directive to control display of errors to the browser. This must be kept to ‘off’ when in production.

<?php

// Inside a 'or' test
mysql_connect('localhost', $user, $pass) or 'die(mysql_error());

// Inside a if test
$result = pg_query( $db, $query );
if( !$result )
{
     echo Erreur SQL: . pg_error();
     'exit;
}

// Changing PHP configuration
ini_set('display_errors', 1);
// This is also a security error : 'false' means actually true.
ini_set('display_errors', 'false');

?>

Error messages should be logged, but not displayed.

See also Error reporting and
List of php.ini directives.
Short name Security/DontEchoError
Themes Analyze, Security
Examples ChurchCRM, Phpdocumentor

9.129. Don’t Send This In Constructor

Don’t use $this` as an argument while in the ‘__construct(). Until the constructor is finished, the object is not finished, and may be in an instable state. Providing it to another code may lead to error.

This is in particular true if the receiving structure put immediately the incoming objet to work, and not simply store it for later use.

<?php

// $this is only provided when Foo is constructed
class Foo {
    private $bar = null;
    private $data = array();

    static public function build($data) {
        $foo = new Foo($data);
        // Can't build in one call. Must make it separate.
        $foo->finalize();
    }

    private function '__construct($data) {
        // $this is provided too early
        $this->data = $data;
    }

    function finalize() {
        $this->bar = new Bar($this);
    }
}

// $this is provided too early, leading to error in Bar
class Foo2 extends Foo {
    private $bar = null;
    private $data = array();

    function '__construct($data) {
        // $this is provided too early
        $this->bar = new Bar($this);
        $this->data = $data;
    }
}

class Bar {
    function '__construct(Foo $foo) {
        // the cache is now initialized with a wrong
        $this->cache = $foo->getIt();
    }
}

?>

See also Don’t pass this out of a constructor.

Short name Classes/DontSendThisInConstructor
Themes Analyze

9.130. Don’t Unset Properties

Avoid unsetting properties. They would go undefined, and raise more warnings.

When getting rid of a property, simply assign it to null. This keeps the property in the object, yet allows existence check without errors.

<?php

class Foo {
    public $a = 1;
}

$a = new Foo();

var_dump((array) $a) ;
// la propriété est reportée, et null
// ['a' => null]

unset($a->a);

var_dump((array) $a) ;
//Empty []

// Check if a property exists
var_dump($a->b === null);

// Same result as above, but with a warning
var_dump($a->c === null);

?>

This analysis works on properties and static properties. It also reports magic properties being unset.

Thanks for [Benoit Burnichon](https://twitter.com/BenoitBurnichon) for the original idea.

Short name Classes/DontUnsetProperties
Themes Analyze
Examples Vanilla, Typo3

9.131. Dont Change The Blind Var

When using a ‘foreach(), the blind variables hold a copy of the original value. It is confusing to modify them, as it seems that the original value may be changed.

When actually changing the original value, use the reference in the foreach definition to make it obvious, and save the final reassignation.

When the value has to be prepared before usage, then save the filtered value in a separate variable. This makes the clean value obvious, and preserve the original value for a future usage.

<?php

// $bar is duplicated and kept
$foo = [1, 2, 3];
foreach($foo as $bar) {
    // $bar is updated but its original value is kept
    $nextBar = $bar + 1;
    print $bar . ' => ' . ($nextBar) . PHP_EOL;
    foobar($nextBar);
}

// $bar is updated and lost
$foo = [1, 2, 3];
foreach($foo as $bar) {
    // $bar is updated but its final value is lost
    print $bar . ' => ' . (++$bar) . PHP_EOL;
    // Now that $bar is reused, it is easy to confuse its value
    foobar($bar);
}

// $bar is updated and kept
$foo = [1, 2, 3];
foreach($foo as &$bar) {
    // $bar is updated and keept
    print $bar . ' => ' . (++$bar) . PHP_EOL;
    foobar($bar);
}

?>
Short name Structures/DontChangeBlindKey
Themes Analyze

9.132. Double Assignation

This happens when a container (variable, property, array index) is assigned with values twice in a row. One of them is probably a debug instruction, that was forgotten.

<?php

// Normal assignation
$a = 1;

// Double assignation
$b = 2;
$b = 3;

?>
Short name Structures/DoubleAssignation
Themes Analyze

9.133. Double Instructions

Twice the same call in a row. This is worth a check.

<?php

?>
Short name Structures/DoubleInstruction
Themes Analyze

9.134. Double array_flip()

Avoid double ‘array_flip() to gain speed. While ‘array_flip() alone is usually useful, a double ‘array_flip() usually is made to handle values and keys.

<?php

// without array_flip
function foo($array, $value) {
    $key = array_search($array, $value);

    if ($key !== false) {
        unset($array[$key]);
    }

    return $array;
}

// double array_flip
// 'array_flip() usage means that $array's values are all unique
function foo($array, $value) {
    $flipped = array_flip($value);
    unset($flipped[$value]);
    return array_flip($flipped);
}

?>
Short name Performances/DoubleArrayFlip
Themes Performances

9.135. Drop Else After Return

Avoid else clause when the then clause returns, but not the else.

The else may simply be set in the main sequence of the function.

This is also true if else has a return, and then not : simply reverse the condition.

<?php

// drop the else
if ($a) {
    return $a;
} else {
    doSomething();
}

// drop the then
if ($b) {
    doSomething();
} else {
    return $a;
}

// return in else and then
if ($a3) {
    return $a;
} else {
    $b = doSomething();
    return $b;
}

?>
Short name Structures/DropElseAfterReturn
Themes Analyze, Suggestions

9.136. Drop Substr Last Arg

Substr() works till the end of the string when the last argument is omitted. There is no need to calculate string size to make this work.

<?php

$string = 'abcdef';

// Extract the end of the string
$cde = substr($string, 2);

// Too much work
$cde = substr($string, 2, strlen($string));

?>

See also substr.

Short name Structures/SubstrLastArg
Themes Suggestions

9.137. Dynamic Library Loading

Loading a variable dynamically requires a lot of care in the preparation of the library name.

In case of injection in the variable, the dynamic loading of a library gives a lot of power to an intruder.

<?php

    // dynamically loading a library
     dl($library. PHP_SHLIB_SUFFIX);

    // dynamically loading ext/vips
     dl('vips.' . PHP_SHLIB_SUFFIX);

?>

See also dl.

Short name Security/DynamicDl
Themes Security

9.138. Echo Or Print

Echo and print have the same functional use. <?= and ‘printf() are also considered in this analysis.

There seems to be a choice that is not enforced : one form is dominant, (> 90%) while the others are rare.

The analyzed code has less than 10% of one of the three : for consistency reasons, it is recommended to make them all the same.

It happens that print, echo or <?= are used depending on coding style and files. One file may be consistently using print, while the others are all using echo.

<?php

echo 'a';
echo 'b';
echo 'c';
echo 'd';
echo 'e';
echo 'f';
echo 'g';
echo 'h';
echo 'i';
echo 'j';
echo 'k';

// This should probably be written 'echo';
print 'l';

?>
Short name Structures/EchoPrintConsistance
Themes Coding Conventions

9.139. Echo With Concat

Optimize your echo’s by not concatenating at echo time, but serving all argument separated. This will save PHP a memory copy.

If values, literals and variables, are small enough, this won’t have visible impact. Otherwise, this is less work and less memory waste.

<?php
  echo $a, ' b ', $c;
?>

instead of

<?php
  echo  $a . ' b ' . $c;
  echo $a b $c;
?>
Short name Structures/EchoWithConcat
Themes Performances, Analyze, Suggestions
ClearPHP no-unnecessary-string-concatenation

9.140. Ellipsis Usage

Usage of the ellipsis keyword. The keyword is three dots : … . It is also named variadic or splat operator.

It may be in function definitions, either in functioncalls.

… allows for packing or unpacking arguments into an array.

<?php

$args = [1, 2, 3];
foo(...$args);
// Identical to foo(1,2,3);

function bar(...$a) {
    // Identical to : $a = 'func_get_args();
}
?>
See also PHP RFC: Syntax for variadic functions,
PHP 5.6 and the Splat Operator, and Variable-length argument lists.
Short name Php/EllipsisUsage
Themes CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55

9.141. Else If Versus Elseif

Always use elseif instead of else and if.

“The keyword elseif SHOULD be used instead of else if so that all control keywords look like single words”. Quoted from the PHP-FIG documentation

<?php

// Using elseif
if ($a == 1) { doSomething(); }
elseif ($a == 2) { doSomethingElseIf(); }
else { doSomethingElse(); }

// Using else if
if ($a == 1) { doSomething(); }
else if ($a == 2) { doSomethingElseIf(); }
else { doSomethingElse(); }

// Using else if, no {}
if ($a == 1)  doSomething();
else if ($a == 2) doSomethingElseIf();
else  doSomethingElse();

?>

.

Short name Structures/ElseIfElseif
Themes Analyze

9.142. Empty Blocks

Full empty block, part of a control structures.

It is recommended to remove those blocks, so as to reduce confusion in the code.

<?php

foreach($foo as $bar) ; // This block seems erroneous
    $foobar++;

if ($a === $b) {
    doSomething();
} else {
    // Empty block. Remove this
}

// Blocks containing only empty expressions are also detected
for($i = 0; $i < 10; $i++) {
    ;
}

// Although namespaces are not control structures, they are reported here
namespace A;
namespace B;

?>
Short name Structures/EmptyBlocks
Themes Analyze

9.143. Empty Classes

Classes that do no define anything at all. Classes that are directly derived from an exception are omitted.

<?php

//Empty class
class foo extends bar {}

//Not an empty class
class foo2 extends bar {
    const FOO = 2;
}

//Not an empty class, as derived from Exception
class barException extends \Exception {}

?>
Short name Classes/EmptyClass
Themes Analyze

9.144. Empty Function

Function or method whose body is empty.

Such functions or methods are rarely useful. As a bare minimum, the function should return some useful value, even if constant.

<?php

// classic empty function
function emptyFunction() {}

class bar {
    // classic empty method
    function emptyMethod() {}

    // classic empty function
    function emptyMethodWithParent() {}
}

class barbar extends bar {
    // NOT an empty method : it overwrites the parent method
    function emptyMethodWithParent() {}
}

?>
Short name Functions/EmptyFunction
Themes Analyze

9.145. Empty Instructions

Empty instructions are part of the code that have no instructions.

This may be trailing semi-colon or empty blocks for if-then structures.

Comments that explains the reason of the situation are not taken into account.

<?php
    $condition = 3;;;;
    if ($condition) { }
?>
Short name Structures/EmptyLines
Themes Dead code, Analyze

9.146. Empty Interfaces

Empty interfaces are a code smell. Interfaces should contains at least a method or a constant, and not be totally empty.

<?php

// an empty interface
interface empty {}

// an normal interface
interface normal {
    public function i() ;
}

// a constants interface
interface constantsOnly {
    const FOO = 1;
}

?>

See also Empty interfaces are bad practice and Blog : Are empty interfaces code smell?.

Short name Interfaces/EmptyInterface
Themes Analyze

9.147. Empty List

Empty list() are not allowed anymore in PHP 7. There must be at least one variable in the list call.

<?php

//Not accepted since PHP 7.0
list() = array(1,2,3);

//Still valid PHP code
list(,$x) = array(1,2,3);

?>
Short name Php/EmptyList
Themes Analyze, CompatibilityPHP70

9.148. Empty Namespace

Declaring a namespace in the code and not using it for structure declarations or global instructions is useless.

Using simple style :

<?php

namespace Y;

class foo {}


namespace X;
// This is useless

?>

Using bracket-style syntax :

<?php

namespace X {
    // This is useless
}

namespace Y {

    class foo {}

}

?>
Short name Namespaces/EmptyNamespace
Themes Analyze, Dead code
ClearPHP no-empty-namespace

9.149. Empty Slots In Arrays

PHP tolerates the last element of an array to be empty.

<?php
    $a = array( 1, 2, 3, );
    $b =      [ 4, 5, ];
?>
Short name Arrays/EmptySlots
Themes Coding Conventions

9.150. Empty Traits

List of all empty trait defined in the code.

<?php

// empty trait
trait t { }

// Another empty trait
trait t2 {
    use t;
}

?>

Such traits may be reserved for future use. They may also be forgotten, and dead code.

Short name Traits/EmptyTrait
Themes Analyze

9.151. Empty Try Catch

The code does try, then catch errors but do no act upon the error.

<?php

try {
    doSomething();
} catch ('Throwable $e) {
    // simply ignore this
}

?>

At worst, the error should be logged, so as to measure the actual usage of the catch expression.

catch( Exception $e) (PHP 5) or catch(‘Throwable $e) with empty catch block should be banned, as they will simply ignore any error.

Short name Structures/EmptyTryCatch
Themes Analyze

9.152. Empty With Expression

‘empty() doesn’t accept expressions until PHP 5.5. Until then, it is necessary to store the result of the expression in a variable and then, test it with ‘empty().

<?php

// PHP 5.5+ 'empty() usage
if (empty(strtolower($b . $c))) {
    doSomethingWithoutA();
}

// Compatible 'empty() usage
$a = strtolower($b . $c);
if (empty($a)) {
    doSomethingWithoutA();
}

?>
Short name Structures/EmptyWithExpression
Themes Suggestions

9.153. Encoded Simple Letters

Some simple letters are written in escape sequence.

Usually, escape sequences are made to encode unusual characters. Using escape sequences for simple characters, like letters or numbers is suspicious.

This analysis also detect unicode codepoint with superfluous leading zeros.

<?php

// This escape sequence makes eval hard to spot
$a = ev1l;
$a('php_info();');

// With a PHP 7.0 unicode code point sequence
$a = ev\u{000041}l;
$a('php_info();');

// With a PHP 5.0+ hexadecimal sequence
$a = ev\x41l;
$a('php_info();');

?>
Short name Security/EncodedLetters
Themes Security

9.154. Error Messages

Error message when an error is reported in the code. Those messages will be read by whoever is triggering the error, and it has to be helpful.

It is a good exercise to read the messages out of context, and try to understand what is about.

<?php

// Not so helpful messages
'die('Here be monsters');
'exit('An error happened');
throw new Exception('Exception thrown at runtime');

?>

Error messages are spotted via ‘die, ‘exit or throw.

Short name Structures/ErrorMessages
Themes ZendFramework

9.155. Eval() Usage

Using ‘eval() is bad for performances (compilation time), for caches (it won’t be compiled), and for security (if it includes external data).

<?php
    // Avoid using incoming data to build the 'eval() expression : any filtering error leads to PHP injection
    $mathExpression = $_GET['mathExpression'];
    $mathExpression = preg_replace('#[^0-9+\-*/\(/)]#is', '', $mathExpression); // expecting 1+2
    $literalCode = '$a = '.$mathExpression.';';
    eval($literalCode);
    echo $a;

    // If eval'ed code is known at compile time, it is best to put it inline
    $literalCode = ''phpinfo();';
    eval($literalCode);

?>

Most of the time, it is possible to replace the code by some standard PHP, like variable variable for accessing a variable for which you have the name. At worse, including a pre-generated file will be faster.

For PHP 7.0 and later, it is important to put ‘eval() in a try..catch expression.

Short name Structures/EvalUsage
Themes Analyze, Performances, Security, Wordpress
ClearPHP no-eval

9.156. Exception Order

When catching exception, the most specialized exceptions must be in the early catch, and the most general exceptions must be in the later catch. Otherwise, the general catches intercept the exception, and the more specialized will not be read.

<?php

class A extends \Exception {}
class B extends A {}

try {
    throw new A();
}
catch(A $a1) { }
catch(B $b2 ) {
    // Never reached, as previous Catch is catching the early worm
}

?>
Short name Exceptions/AlreadyCaught
Themes Dead code
Examples Woocommerce

9.157. Exit() Usage

Using ‘exit or ‘die() in the code makes the code untestable (it will ‘break unit tests). Moreover, if there is no reason or string to display, it may take a long time to spot where the application is stuck.

<?php

// Throw an exception, that may be caught somewhere
throw new \Exception('error');

// Dying with error message.
'die('error');

function foo() {
    //exiting the function but not dying
    if (somethingWrong()) {
        return true;
    }
}
?>

Try exiting the function/class with return, or throw exception that may be caught later in the code.

Short name Structures/ExitUsage
Themes Analyze, ZendFramework
ClearPHP no-exit

9.158. Exponent Usage

Usage of the ‘** operator or **=, to make exponents.

<?php

$eight = 2 '** 3;

$sixteen = 4;
$sixteen \*\*\= 2;

?>

See also Arithmetic Operators.

Short name Php/ExponentUsage
Themes CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55

9.159. Failed Substr Comparison

The extracted string must be of the size of the compared string.

This is also true for negative lengths.

<?php

// Possible comparison
if (substr($a, 0, 3) === 'abc') { }
if (substr($b, 4, 3) === 'abc') { }

// Always failing
if (substr($a, 0, 3) === 'ab') { }
if (substr($a, 3, -3) === 'ab') { }

// Omitted in this analysis
if (substr($a, 0, 3) !== 'ab') { }

?>
Short name Structures/FailingSubstrComparison
Themes Analyze
Examples Zurmo, MediaWiki

9.160. Fetch One Row Format

When reading results with ext/Sqlite3, it is recommended to explicitely request SQLITE3_NUM or SQLITE3_ASSOC, while avoiding the default value and SQLITE3_BOTH.

<?php

$res = $database->query($query);

// Fastest version, but less readable
$row = $res->fetchArray(\SQLITE3_NUM);
// Almost the fastest version, and more readable
$row = $res->fetchArray(\SQLITE3_ASSOC);

// Default version. Quite slow
$row = $res->fetchArray();

// Worse case
$row = $res->fetchArray(\SQLITE3_BOTH);

?>

This is a micro-optimisation. The difference may be visible with 200k rows fetches, and measurable with 10k.

Short name Performances/FetchOneRowFormat
Themes Performances

9.161. Find Key Directly

No need for a ‘foreach() to search for a key.

PHP offers two solutions : ‘array_search() and ‘array_keys(). Array_search() finds the first key that fits a value, and array_keys returns all the keys.

<?php

$array = ['a', 'b', 'c', 'd', 'e'];

print array_search($array, 'c');
// print 2 => 'c';

print_r(array_keys($array, 'c'));
// print 2 => 'c';

?>

See also array_search and array_keys.

Short name Structures/GoToKeyDirectly
Themes Suggestions

9.162. For Using Functioncall

It is recommended to avoid functioncall in the ‘for() statement.

<?php

// Fastest way
$nb = count($array);
for($i = 0; $i < $nb; ++$i) {
    doSomething($i);
}

// Same as above, but slow
for($i = 0; $i < count($array); ++$i) {
    doSomething($i);
}

// Same as above, but slow
foreach($portions as &$portion) {
    // here, 'array_sum() doesn't depends on the $grade. It should be out of the loop
    $portion = $portion / array_sum($portions);
}

$total = array_sum($portion);
foreach($portion as &$portion) {
    $portion = $portion / $total;
}

?>

This is true with any kind of functioncall that returns the same value throughout the loop.

Short name Structures/ForWithFunctioncall
Themes Analyze, Performances
ClearPHP no-functioncall-in-loop

9.163. Foreach Don’t Change Pointer

A foreach loop won’t change the internal pointer of the array, as it works on a copy of the source. Hence, applying array pointer’s functions such as ‘current() or ‘next() to the source array won’t have the same behavior in PHP 5 than PHP 7.

This anly applies when a ‘foreach() by reference is used.

<?php

$numbers = range(1, 10);
next($numbers);
foreach($numbers as &$number){
    print $number;
    print current($numbers).\n; // Always
}

?>

See also foreach no longer changes the internal array pointer.

Short name Php/ForeachDontChangePointer
Themes CompatibilityPHP70

9.164. Foreach Needs Reference Array

When using foreach with a reference as value, the source must be a referenced array, which is a variable (or array or property or static property). When the array is the result of an expression, the array is not kept in memory after the foreach loop, and any change made with & are lost.

This will do nothing

<?php
    foreach(array(1,2,3) as &$value) {
        $value *= 2;
    }
?>

This will have an actual effect

<?php
    $array = array(1,2,3);
    foreach($array as &$value) {
        $value *= 2;
    }
?>
Short name Structures/ForeachNeedReferencedSource
Themes Analyze

9.165. Foreach On Object

Foreach on object looks like a typo. This is particularly true when both object and member are variables.

Foreach on an object member is a legit PHP syntax, though it is very rare : blind variables rarely have to be securing in an object to be processed.

<?php

// Looks suspicious
foreach($array as $o -> $b) {
    doSomething();
}

// This is the real thing
foreach($array as $o => $b) {
    doSomething();
}

?>
Short name Php/ForeachObject
Themes Analyze

9.166. Foreach Reference Is Not Modified

Foreach statement may loop using a reference, especially when the loop has to change values of the array it is looping on.

In the spotted loop, reference are used but never modified. They may be removed.

<?php

$letters = range('a', 'z');

// $letter is not used here
foreach($letters as &$letter) {
    $alphabet .= $letter;
}

// $letter is actually used here
foreach($letters as &$letter) {
    $letter = strtoupper($letter);
}

?>
Short name Structures/ForeachReferenceIsNotModified
Themes Analyze

9.167. Foreach With list()

Foreach loops have the ability to use list as blind variables. This syntax assign directly array elements to various variables.

PHP 5.5 introduced the usage of list in ‘foreach() loops. Until PHP 7.1, it was not possible to use non-numerical arrays as list() wouldn’t support string-indexed arrays.

<?php
    // PHP 5.5 and later, with numerically-indexed arrays
    foreach($array as list($a, $b)) {
        // do something
    }


    // PHP 7.1 and later, with arrays
    foreach($array as list('col1' => $a, 'col3' => $b)) { // 'col2 is ignored'
        // do something
    }
?>

Previously, it was compulsory to extract the data from the blind array :

<?php
    foreach($array as $c) {
        list($a, $b) = $c;
        // do something
    }
?>
Short name Structures/ForeachWithList
Themes CompatibilityPHP53, CompatibilityPHP54, Suggestions

9.168. Forgotten Interface

The following classes have been found implementing an interface’s methods, though it doesn’t explicitely implements this interface. This may have been forgotten.

<?php

interface i {
    function i();
}

// i is not implemented and declared
class foo {
    function i() {}
    function j() {}
}

// i is implemented and declared
class foo implements i {
    function i() {}
    function j() {}
}

?>
Short name Interfaces/CouldUseInterface
Themes Analyze

9.169. Forgotten Thrown

An exception is instantiated, but not thrown.

<?php

class MyException extends \Exception { }

if ($error !== false) {
    // This looks like 'throw' was omitted
    new MyException();
}

?>
Short name Exceptions/ForgottenThrown
Themes Analyze

9.170. Forgotten Visibility

Some classes elements (property, method, constant) are missing their explicit visibility.

By default, it is public. It should at least be mentioned as public, or may be reviewed as protected or private.

Class constants support also visibility since PHP 7.1.

final, static and abstract are not counted as visibility. Only public, private and protected. The PHP 4 var keyword is counted as undefined.

Traits, classes and interfaces are checked.

<?php

// Explicit visibility
class X {
    protected sconst NO_VISIBILITY_CONST = 1; // For PHP 7.2 and later

    private $noVisibilityProperty = 2;

    public function Method() {}
}

// Missing visibility
class X {
    const NO_VISIBILITY_CONST = 1; // For PHP 7.2 and later

    var $noVisibilityProperty = 2; // Only with var

    function NoVisibilityForMethod() {}
}

?>

See also Visibility and Understanding The Concept Of Visibility In Object Oriented PHP.

Short name Classes/NonPpp
Themes Analyze
ClearPHP always-have-visibility

9.171. Forgotten Whitespace

White spaces have been left at either end of a file : before the PHP opening tag, or after the closing tag.

Usually, such white space are forgotten, and may end up summoning the infamous ‘headers already sent’ error. It is better to remove them.

<?php
    // This script has no forgotten whitespace, not at the beginning
    function foo() {}

    // This script has no forgotten whitespace, not at the end
?>

See also How to fix Headers already sent error in PHP.

Short name Structures/ForgottenWhiteSpace
Themes Analyze

9.172. Fully Qualified Constants

Constants defined with their namespace.

When defining constants with ‘define() function, it is possible to include the actual namespace :

<?php

define('a\b\c', 1);

?>

However, the name should be fully qualified without the initial . Here, abc constant will never be accessible as a namespace constant, though it will be accessible via the ‘constant() function.

Also, the namespace will be absolute, and not a relative namespace of the current one.

Short name Namespaces/ConstantFullyQualified
Themes Analyze

9.173. Function Subscripting

It is possible to use the result of a methodcall directly as an array, without storing the result in a temporary variable.

This works, given that the method actually returns an array.

This syntax was not possible until PHP 5.4. Until then, it was compulsory to store the result in a variable first. Although this is now superfluous, it has been a standard syntax in PHP, and is still being used.

<?php

function foo() {
    return array(1 => 'a', 'b', 'c');
}

echo foo()[1]; // displays 'a';

// Function subscripting, the old way
function foo() {
    return array(1 => 'a', 'b', 'c');
}

$x = foo();
echo $x[1]; // displays 'a';

?>

Storing the result in a variable is still useful if the result is actually used more than once.

Short name Structures/FunctionSubscripting
Themes CompatibilityPHP53

9.174. Function Subscripting, Old Style

Since PHP 5.4, it is now possible use function results as an array, and access directly its element :

<?php

function foo() {
    return array(1 => 'a', 'b', 'c');
}

echo foo()[1]; // displays 'a';

// Function subscripting, the old way
function foo() {
    return array(1 => 'a', 'b', 'c');
}

$x = foo();
echo $x[1]; // displays 'a';

?>
Short name Structures/FunctionPreSubscripting
Themes Analyze

9.175. Functions Removed In PHP 5.4

Those functions were removed in PHP 5.4.

<?php

// Deprecated as of PHP 5.4.0
$link = mysql_connect('localhost', 'mysql_user', 'mysql_password');
$db_list = mysql_list_dbs($link);

while ($row = mysql_fetch_object($db_list)) {
     echo $row->Database . \n;
}

?>

See also Deprecated features in PHP 5.4.x.

Short name Php/Php54RemovedFunctions
Themes CompatibilityPHP54

9.176. Functions Removed In PHP 5.5

Those functions were removed in PHP 5.5.

Short name Php/Php55RemovedFunctions
Themes CompatibilityPHP55

9.177. Getting Last Element

Getting the last element of an array is done with ‘count() or ‘end().

<?php

$array = [1, 2, 3];

// Best solutions, just as quick as each other
$last = $array[count($array) - 1];
$last = end($array);

// Bad solutions

// popping, but restoring the value.
$last = array_pop($array);
$array[] = $last;

// array_unshift would be even worse

// reversing array
$last = array_reverse($array)[0];

// slicing the array
$last = array_slice($array, -1)[0]',
$last = current(array_slice($array, -1));
);

?>
Short name Arrays/GettingLastElement
Themes Performances

9.178. Global Inside Loop

The global keyword must be out of loops. It is evaluated each loop, slowing the whole process.

<?php

// Good idea, global is used once
global $total;
foreach($a as $b) {
    $total += $b;
}

// Bad idea, this is slow.
foreach($a as $b) {
    global $total;
    $total += $b;
}
?>
Short name Structures/GlobalOutsideLoop
Themes Performances

9.179. Global Usage

List usage of globals variables, with global keywords or direct access to $GLOBALS.

<?php
$a = 1; /* global scope */

function test()
{
    echo $a; /* reference to local scope variable */
}

test();

?>

It is recommended to avoid using global variables, at it makes it very difficult to track changes in values across the whole application.

See also Variable scope.

Short name Structures/GlobalUsage
Themes Analyze
ClearPHP no-global

9.180. Group Use Declaration

The group use declaration is used in the code.

<?php

// Adapted from the RFC documentation
// Pre PHP 7 code
use some\name_space\ClassA;
use some\name_space\ClassB;
use some\name_space\ClassC as C;

use function some\name_space\fn_a;
use function some\name_space\fn_b;
use function some\name_space\fn_c;

use const some\name_space\ConstA;
use const some\name_space\ConstB;
use const some\name_space\ConstC;

// PHP 7+ code
use some\name_space\{ClassA, ClassB, ClassC as C};
use function some\name_space\{fn_a, fn_b, fn_c};
use const some\name_space\{ConstA, ConstB, ConstC};

?>

See also Group Use Declaration RFC and Using namespaces: Aliasing/Importing.

Short name Php/GroupUseDeclaration
Themes CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56

9.181. Group Use Trailing Comma

The usage of a final empty slot in array() was allowed with use statements. This works in PHP 7.2 and more recent.

Although this empty instruction is ignored at execution, this allows for clean presentation of code, and short diff when committing in a VCS.

<?php

// Valid in PHP 7.2 and more recent.
use a\b\{c,
         d,
         e,
         f,
        };

// This won't compile in 7.1 and older.

?>

See also Trailing Commas In List Syntax and Revisit trailing commas in function arguments.

Short name Php/GroupUseTrailingComma
Themes CompatibilityPHP53, CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56

9.182. Hardcoded Passwords

Hardcoded passwords in the code.

Hardcoding passwords is a bad idea. Not only it make the code difficult to change, but it is an information leak. It is better to hide this kind of information out of the code.

<?php

$ftp_server = '300.1.2.3';   //
$conn_id = ftp_connect($ftp_server);

// login with username and password
$login_result = ftp_login($conn_id, 'login', 'password');

?>
Short name Functions/HardcodedPasswords
Themes Analyze, Security
ClearPHP no-hardcoded-credential

9.183. Hash Algorithms

There is a long but limited list of hashing algorithm available to PHP. The one found below doesn’t seem to be existing.

Short name Php/HashAlgos
Themes Analyze

9.184. Hash Algorithms Incompatible With PHP 5.3

List of hash algorithms incompatible with PHP 5.3. They were introduced in newer version, and, as such, are not available with older versions.

fnv132, fnv164 and joaat were added in PHP 5.4.

<?php

// Valid in PHP 5.4 +
hash('joaat', 'string');

// Valid in PHP all versions
hash('crc32', 'string');

?>
Short name Php/HashAlgos53
Themes CompatibilityPHP53, CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56

9.185. Hash Algorithms Incompatible With PHP 5.4/5

List of hash algorithms incompatible with PHP 5.4 and 5.5. They were introduced in newer version, or removed in PHP 5.4. As such, they are not available with older versions.

Short name Php/HashAlgos54
Themes CompatibilityPHP54, CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP55, CompatibilityPHP56

9.186. Hash Will Use Objects

The ext/hash <http://www.php.net/hash> extension used resources, and is being upgraded to use resources.

<?php

// Post 7.2 code
    $hash = hash_init('sha256');
    if (!is_object($hash)) {
        trigger_error('error');
    }
    hash_update($hash, $message);

// Pre-7.2 code
    $hash = hash_init('md5');
    if (!is_resource($hash)) {
        trigger_error('error');
    }
    hash_update($hash, $message);

?>

See also Move ext/hash from resources to objects.

Short name Php/HashUsesObjects
Themes CompatibilityPHP72

9.187. Heredoc Delimiter

Heredoc and Nowdoc expressions may use a variety of delimiters.

There seems to be a standard delimiter in the code, and some exceptions : one or several forms are dominant (> 90%), while the others are rare.

The analyzed code has less than 10% of the rare delimiters. For consistency reasons, it is recommended to make them all the same.

Generally, one or two delimiters are used, with generic value. It is recommended to use a humanly readable delimiter : SQL, HTML, XML, GREMLIN, etc. This helps readability in the code.

<?php

echo <<<SQL
SELECT * FROM table1;
SQL;

echo <<<SQL
SELECT * FROM table2;
SQL;

echo <<<SQL
SELECT * FROM table3;
SQL;

echo <<<SQL
SELECT * FROM table4;
SQL;

echo <<<SQL
SELECT * FROM table5;
SQL;

echo <<<SQL
SELECT * FROM table11;
SQL;

echo <<<SQL
SELECT * FROM table12;
SQL;

echo <<<SQL
SELECT * FROM table13;
SQL;

// Nowdoc
echo <<<'SQL'
SELECT * FROM table14;
SQL;

echo <<<SQL
SELECT * FROM table15;
SQL;


echo <<<HEREDOC
SELECT * FROM table215;
HEREDOC;

?>
Short name Structures/HeredocDelimiterFavorite
Themes Coding Conventions

9.188. Hexadecimal In String

Mark strings that may be confused with hexadecimal.

Until PHP 7.0, PHP recognizes hexadecimal numbers inside strings, and converts them accordingly.

PHP 7.0 and until 7.1, converts the string to 0, silently.

PHP 7.1 and later, emits a ‘A non-numeric value encountered’ warning, and convert the string to 0.

<?php
    $a = '0x0030';
    print $a + 1;
    // Print 49

    $c = '0x0030zyc';
    print $c + 1;
    // Print 49

    $b = 'b0x0030';
    print $b + 1;
    // Print 0
?>
Short name Type/HexadecimalString
Themes CompatibilityPHP70, CompatibilityPHP71

9.189. Hidden Use Expression

The use expression for namespaces should always be at te beginning of the namespace block.

It is where everyone expect them, and it is less confusing than having them at various levels.

<?php

// This is visible
use A;

class B {}

// This is hidden
use C as D;

class E extends D {
    use traitT; // This is a use for a trait

    function foo() {
        // This is a use for a closure
        return function ($a) use ($b) {}
    }
}

?>
Short name Namespaces/HiddenUse
Themes Analyze

9.190. Htmlentities Calls

‘htmlentities() and ‘htmlspecialchars() are used to prevent injecting special characters in HTML code. As a bare minimum, they take a string and encode it for HTML.

The second argument of the functions is the type of protection. The protection may apply to quotes or not, to HTML 4 or 5, etc. It is highly recommended to set it explicitly.

The third argument of the functions is the encoding of the string. In PHP 5.3, it is ISO-8859-1, in 5.4, was UTF-8, and in 5.6, it is now default_charset, a php.ini configuration that has the default value of UTF-8. It is highly recommended to set this argument too, to avoid distortions from the configuration.

<?php
$str = 'A quote is <b>bold</b>';

// Outputs, without depending on the php.ini: A &#039;quote&#039; is &lt;b&gt;bold&lt;/b&gt;
echo htmlentities($str, ENT_QUOTES, 'UTF-8');

// Outputs, while depending on the php.ini: A quote is &lt;b&gt;bold&lt;/b&gt;
echo htmlentities($str);

?>

Also, note that arguments 2 and 3 are constants and string (respectively), and should be issued from the list of values available in the manual. Other values than those will make PHP use the default values.

See also htmlentities and htmlspecialchars.

Short name Structures/Htmlentitiescall
Themes Analyze

9.191. Identical Conditions

These logical expressions contain members that are identical.

This means those expressions may be simplified.

<?php

// twice $a
if ($a || $b || $c || $a) {  }

// Hiding in parenthesis is bad
if (($a) ^ ($a)) {}

// expressions may be large
if ($a === 1 && 1 === $a) {}

?>
Short name Structures/IdenticalConditions
Themes Analyze
Examples WordPress, Dolibarr, Mautic

9.192. Identical Consecutive Expression

Identical consecutive expressions are worth being checked.

They may be a copy/paste with unmodified content. When the content has to be duplicated, it is recommended to avoid executing the expression again, and just access the cached result.

<?php

$current  = $array[$i];
$next     = $array[$i + 1];
$nextnext = $array[$i + 1]; // OOps, nextnext is wrong.

// Initialization
$previous = foo($array[1]); // previous is initialized with the first value on purpose
$next     = foo($array[1]); // the second call to foo() with the same arguments should be avoided
// the above can be rewritten as :
$next     = $previous; // save the processing.

for($i = 1; $i < 200; ++$i) {
    $next = doSomething();
}
?>
Short name Structures/IdenticalConsecutive
Themes Analyze

9.193. Identical On Both Sides

Operands should be different when comparing or making a logical combination. Of course, the value each operand holds may be identical. When the same operand appears on both sides of the expression, the result is know before execution.

<?php

// Trying to confirm consistency
if ($login == $login) {
    doSomething();
}

// Works with every operators
if ($object->login( ) !== $object->login()) {
    doSomething();
}

if ($sum >= $sum) {
    doSomething();
}

//
if ($mask && $mask) {
    doSomething();
}

if ($mask || $mask) {
    doSomething();
}

?>
Short name Structures/IdenticalOnBothSides
Themes Analyze
Examples phpMyAdmin

9.194. If With Same Conditions

Successive If / then structures that have the same condition may be either merged or have one of the condition changed.

<?php

if ($a == 1) {
    doSomething();
}

if ($a == 1) {
    doSomethingElse();
}

// May be replaced by
if ($a == 1) {
    doSomething();
    doSomethingElse();
}

?>

Note that if the values used in the condition have been modified in the first if/then structure, the two distinct conditions may be needed.

<?php

// May not be merged
if ($a == 1) {
    // Check that this is really the situation
    $a = checkSomething();
}

if ($a == 1) {
    doSomethingElse();
}

?>
Short name Structures/IfWithSameConditions
Themes Analyze

9.195. Iffectations

Affectations that appears in a condition.

Iffectations are a way to do both a test and an affectations. They may also be typos, such as if ($x = 3) { … }, leading to a constant condition.

<?php

// an iffectation : assignation in a If condition
if($connexion = mysql_connect($host, $user, $pass)) {
    $res = mysql_query($connexion, $query);
}

// Iffectation may happen in while too.
while($row = mysql_fetch($res)) {
    $store[] = $row;
}

?>
Short name Structures/Iffectation
Themes Analyze

9.196. Illegal Name For Method

PHP has reserved usage of methods starting with __ for magic methods. It is recommended to avoid using this prefix, to prevent confusions.

<?php

class foo{
    // Constructor
    function '__construct() {}

    // Constructor's typo
    function __constructor() {}

    // Illegal function name, even as private
    private function __bar() {}
}

?>
Short name Classes/WrongName
Themes Analyze

9.197. Implement Is For Interface

With class heritage, implements should be used for interfaces, and extends with classes.

PHP defers the implements check until execution : the code in example does lint, but won,t run.

<?php

class x {}

interface y {}

// This is wrong
class z implements x {}

?>
Short name Classes/ImplementIsForInterface
Themes Analyze

9.198. Implemented Methods Are Public

Class methods that are defined in an interface must be public. They cannot be either private, nor protected.

This error is not reported by lint, but is reported at execution time.

<?php

interface i {
    function foo();
}

class X {
    // This method is defined in the interface : it must be public
    protected function foo() {}

    // other methods may be private
    private function bar() {}
}

?>
Short name Classes/ImplementedMethodsArePublic
Themes Analyze

9.199. Implicit Global

Global variables, that are used in local scope with global keyword, but are not declared as global in the global scope. They may be mistaken with distinct values, while, in PHP, variables in the global scope are truly global.

<?php

// This is implicitely global
$implicitGlobal = 1;

global $explicitGlobal;
$explicitGlobal = 2;

foo();
echo $explicitFunctionGlobal;

function foo() {
    // This global is needed, but not the one in the global space
    global $implicitGlobal, $explicitGlobal, $explicitFunctionGlobal;

    // This won't be a global, as it must be 'global' in a function scope
    $notImplicitGlobal = 3;
    $explicitFunctionGlobal = 3;
}

?>
Short name Structures/ImplicitGlobal
Themes Analyze

9.200. Implied If

It is confusing to emulate if/then with boolean operators.

It is possible to emulate a if/then structure by using the operators ‘and’ and ‘or’. Since optimizations will be applied to them : when the left operand of ‘and’ is false, the right one is not executed, as its result is useless; when the left operand of ‘or’ is true, the right one is not executed, as its result is useless;

However, such structures are confusing. It is easy to misread them as conditions, and ignore an important logic step.

<?php

// Either connect, or 'die
mysql_connect('localhost', $user, $pass) or 'die();

// Defines a constant if not found.
defined('SOME_CONSTANT') and define('SOME_CONSTANT', 1);

// Defines a default value if provided is empty-ish
// Warning : this is
$user = $_GET['user'] || 'anonymous';

?>

It is recommended to use a real ‘if then’ structures, to make the condition readable.

Short name Structures/ImpliedIf
Themes Analyze
ClearPHP no-implied-if

9.201. Inclusion Wrong Case

Inclusion should follow exactly the case of included files and path. This prevents the infamous case-sensitive filesystem bug, where files are correctly included in a case-insensitive system, and failed to be when moved to production.

<?php

// There must exist a path called path/to and a file library.php with this case
include path/to/library.php;

?>
Short name Files/InclusionWrongCase
Themes Analyze

9.202. Incompilable Files

Files that cannot be compiled, and, as such, be run by PHP. Scripts are linted against various versions of PHP.

This is usually undesirable, as all code must compile before being executed. It may simply be that such files are not compilable because they are not yet ready for an upcoming PHP version.

<?php

// Can't compile this : Print only accepts one argument
print $a, $b, $c;

?>

Code that is incompilable with older PHP versions means that the code is breaking backward compatibility : good or bad is project decision.

When the code is used as a template for PHP code generation, for example at installation time, it is recommended to use a distinct file extension, so as to distinguish them from actual PHP code.

Short name Php/Incompilable
Themes Analyze
ClearPHP no-incompilable

9.203. Indices Are Int Or String

Indices in an array notation such as $array[‘indice’] may only be integers or string.

Boolean, Null or float will be converted to their integer or string equivalent.

<?php
    $a = [true => 1,
          1.0  => 2,
          1.2  => 3,
          1    => 4,
          '1'  => 5,
          0.8  => 6,
          0x1  => 7,
          01   => 8,

          null  => 1,
          ''    => 2,

          false => 1,
          0     => 2,

          '0.8' => 3,
          '01'  => 4,
          '2a'  => 5
          ];

    print_r($a);
?>::


Array
(
    [1] => 8
    [0] => 2
    [] => 2
    [0.8] => 3
    [01] => 4
    [2a] => 5
)

Decimal numbers are rounded to the closest integer; Null is transtyped to ‘’ (empty string); true is 1 and false is 0; Integers in strings are transtyped, while partial numbers or decimals are not analyzed in strings.

As a general rule of thumb, only use integers or strings that don’t look like integers.

This analyzer may find constant definitions, when available.

Short name Structures/IndicesAreIntOrString
Themes Analyze

9.204. Indirect Injection

Look for injections through indirect usage for GPRC values ($_GET, $_POST, $_REQUEST, $_COOKIE).

<?php

$a = $_GET['a'];
echo $a;

?>
Short name Security/IndirectInjection
Themes Security

9.205. Instantiating Abstract Class

PHP cannot instantiate an abstract class.

The classes are actually abstract classes, and should be derived into a concrete class to be instantiated.

<?php

abstract class Foo {
    protected $a;
}

class Bar extends Foo {
    protected $b;
}

// instantiating a concrete class.
new Bar();

// instantiating an abstract class.
// In real life, this is not possible also because the definition and the instantiation are in the same file
new Foo();

?>

See also Class Abstraction.

Short name Classes/InstantiatingAbstractClass
Themes Analyze

9.206. Integer As Property

It is backward incompatible to use integers are property names. This feature was introduced in PHP 7.2.

If the code must be compatible with previous versions, avoir casting arrays to object.

<?php

// array to object
$arr = [0 => 1];
$obj = (object) $arr;
var_dump(
    $obj,
    $obj->{'0'}, // PHP 7.2+ accessible
    $obj->{0} // PHP 7.2+ accessible

    $obj->{'b'}, // always been accessible
);
?>
Short name Classes/IntegerAsProperty
Themes CompatibilityPHP53, CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56

9.207. Interpolation

The following strings contain variables that are will be replaced. However, the following characters are ambiguous, and may lead to confusion.

<?php

class b {
    public $b = 'c';
    function '__toString() { return '__CLASS__; }
}
$x = array(1 => new B());

// -> after the $x[1] looks like a 2nd dereferencing, but it is not.
print $x[1]->b;
// displays : b->b

print {$x[1]->b};
// displays : c

?>

It is advised to add curly brackets around those structures to make them non-ambiguous.

See also Double quoted.

Short name Type/StringInterpolation
Themes Coding Conventions

9.208. Invalid Constant Name

According to PHP’s manual, constant names, ‘ A valid constant name starts with a letter or underscore, followed by any number of letters, numbers, or underscores.’.

Constant, when defined using ‘define() function, must follow this regex ::

/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/
<?php

define('+3', 1); // wrong constant!

echo constant('+3'); // invalid constant access

?>
Short name Constants/InvalidName
Themes Analyze

9.209. Invalid Octal In String

Any octal sequence inside a string can’t be beyond 7. Those will be a fatal error at parsing time.

This is true, starting with PHP 7.1. In PHP 7.0 and older, those sequences were silently adapted (divided by 0).

<?php

// Emit no error in PHP 7.1
echo 0; // @

// Emit an error in PHP 7.1
echo 0; // @

?>

See also Integers.

Short name Type/OctalInString
Themes CompatibilityPHP71

9.210. Invalid Regex

The PCRE regex doesn’t compile. It isn’t a valid regex.

Several reasons may lead to this situation : syntax error, Unknown modifier, missing parenthesis or reference.

<?php

// valid regex
preg_match('/[abc]/', $string);

// invalid regex (missing terminating ] for character class
preg_match('/[abc/', $string);

?>

Regex are check with the Exakat version of PHP.

Dynamic regex are only checked for simple values. Dynamic values may eventually generate a compilation error.

Short name Structures/InvalidRegex
Themes Analyze

9.211. Is Actually Zero

This addition actually may be simplified because one term is actually negated by another.

This kind of error happens when the expression is very large : the more terms are included, the more chances are that some auto-annihilation happens.

This error may also be a simple typo : for example, calculating the difference between two consecutive terms.

<?php

// This is quite obvious
$a = 2 - 2;

// This is obvious too. This may be a typo-ed difference between two consecutive terms.
// Could have been $c = $fx[3][4] - $fx[3][3] or $c = $fx[3][5] - $fx[3][4];
$c = $fx[3][4] - $fx[3][4];

// This is less obvious
$a = $b[3] - $c + $d->foo(1,2,3) + $c + $b[3];

?>
Short name Structures/IsZero
Themes Analyze

9.212. Is Zend Framework 1 Controller

Mark a class as being a Zend Framework Controller.

<?php

class AController extends Zend_Controller_Action {
    // Controller code
}

?>
Short name ZendF/IsController
Themes ZendFramework

9.213. Is Zend Framework 1 Helper

Mark a class as being a Zend Framework Helper.

<?php

class AnHelper extends Zend_View_Helper_Abstract {
    // Controller code
}

?>
Short name ZendF/IsHelper
Themes ZendFramework

9.214. Is Zend View File

Mark files as View when then have the .phtml extension.

Zend Views are build with call to $this, without any class or trait. Indeed, the file will be included just in time, and its properties and methods will then be provided.

<?php

echo $this->title;

?>

See also Zend View.

Short name ZendF/IsView
Themes ZendFramework

9.215. Isset Multiple Arguments

‘isset() may be used with multiple arguments and acts as a AND.

<?php

// 'isset without and
if ('isset($a, $b, $c)) {
    // doSomething()
}

// 'isset with and
if ('isset($a) && 'isset($b) && 'isset($c)) {
    // doSomething()
}

?>

See also isset <http://www.php.net/’isset <http://www.php.net/isset>`_>`_.

Short name Php/IssetMultipleArgs
Themes Suggestions

9.216. Isset With Constant

Until PHP 7, it was possible to use arrays as constants, but it was not possible to test them with ‘isset.

<?php
const X = [1,2,3];

if ('isset(X[4])) {}
?>

This would yield an error :

Fatal error: Cannot use ‘isset() on the result of an expression (you can use “null !== expression” instead) in test.php on line 7

This is a backward incompatibility.

Short name Structures/IssetWithConstant
Themes CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56

9.217. Join file()

Applying join(‘’, ) or implode(‘’, ) to the result of ‘file() provides the same results than using ‘file_get_contents(), but at a higher cost of memory and processing.

If the delimiter is not ‘’, then ‘implode() and ‘file() are a better solution than ‘file_get_contents() and ‘str_replace() or ‘nl2br().

<?php

// memory intensive
$content = file_get_contents('path/to/file.txt');

// memory and CPU intensive
$content = join('', file('path/to/file.txt'));

// Consider reading the data line by line and processing it along the way,
// to save memory
$fp = fopen('path/to/file.txt', 'r');
while($line = fget($fp)) {
    // process a line
}
fclose($fp);

?>

Always use ‘file_get_contents() to get the content of a file as a string.

Short name Performances/JoinFile
Themes Performances
Examples WordPress, SPIP, ExpressionEngine, PrestaShop

9.218. List Short Syntax

Usage of short syntax version of list().

<?php

// PHP 7.1 short list syntax
// PHP 7.1 may also use key => value structures with list
[$a, $b, $c] = ['2', 3, '4'];

// PHP 7.0 list syntax
list($a, $b, $c) = ['2', 3, '4'];

?>
Short name Php/ListShortSyntax
Themes CompatibilityPHP53, CompatibilityPHP70, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56

9.219. List With Appends

List() behavior has changed in PHP 7.0 and it has impact on the indexing when list is used with the [] operator.

<?php

$x = array();
list($x[], $x[], $x[]) = [1, 2, 3];

print_r($x);

?>

In PHP 7.0, results are ::

Array
(
    [0] => 1
    [1] => 2
    [2] => 3
)

In PHP 5.6, results are ::

Array
(
    [0] => 3
    [1] => 2
    [2] => 1
)
Short name Php/ListWithAppends
Themes CompatibilityPHP70

9.220. List With Keys

Setting keys when using list() is a PHP 7.1 feature.

<?php

// PHP 7.1 and later only
list('a' => $a, 'b' => $b) = ['b' => 1, 'c' => 2, 'a' => 3];

?>
Short name Php/ListWithKeys
Themes CompatibilityPHP53, CompatibilityPHP70, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56

9.221. List With Reference

Support for references in list calls is not backward compatible with older versions of PHP. The support was introduced in PHP 7.3.

<?php

$a = [1,2,3];

[$c, $d, $e] = $a;

$d++;
echo $a[2]; // Displays 4

?>

See also list() Reference Assignment.

Short name Php/ListWithReference
Themes CompatibilityPHP53, CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP72, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56

9.222. Local Globals

A global variable is used locally in a method.

Either the global keyword has been forgotten, or the local variable should be renamed in a less ambiguous manner.

Having both a global and a local variable with the same name is legit. PHP keeps the contexts separated, and it processes them independantly.

However, in the mind of the coder, it is easy to mistake the local variable $x and the global variable $x. May they be given different meaning, and this is an error-prone situation.

It is recommended to keep the global variables’s name distinct from the local variables.

<?php

// This is actualy a global variable
$variable = 1;
$globalVariable = 2;

function foo() {
    global $globalVariable2;

    $variable = 4;
    $localVariable = 3;

    // This always displays 423, instead of 123
    echo $variable .' ' . $globalVariable . ' ' . $localVariable;
}

?>
Short name Variables/LocalGlobals
Themes Analyze

9.223. Locally Unused Property

Those properties are defined in a class, and this class doesn’t have any method that makes use of them.

While this is syntacticly correct, it is unusual that defined ressources are used in a child class. It may be worth moving the definition to another class, or to move accessing methods to the class.

<?php

class foo {
    public $unused, $used;// property $unused is never used in this class

    function bar() {
        $this->used++; // property $used is used in this method
    }
}

class foofoo extends foo {
    function bar() {
        $this->unused++; // property $unused is used in this method, but defined in the parent class
    }
}

?>
Short name Classes/LocallyUnusedProperty
Themes Analyze, Dead code

9.224. Logical Mistakes

Avoid logical mistakes within long expressions.

Sometimes, the logic is not what it seems. It is important to check the actual impact of every part of the logical expression. Do not hesitate to make a table with all possible cases. If those cases are too numerous, it may be time to rethink the whole expression.

<?php

// Always false
if ($a != 1 || $a != 2) { }

// $a == 1 is useless
if ($a == 1 || $a != 2) {}

// Always false
if ($a == 1 && $a == 2) {}

// $a != 2 is useless
if ($a == 1 && $a != 2) {}

?>

Based on article from Andrey Karpov Logical Expressions in C/C++. Mistakes Made by Professionals

Short name Structures/LogicalMistakes
Themes Analyze

9.225. Logical Should Use Symbolic Operators

Logical operators come in two flavors : and / &&, || / or, ^ / xor. However, they are not exchangeable, as && and and have different precedence.

<?php

// Avoid lettered operator, as they have lower priority than expected
$a = $b and $c;
// $a === 3

$a = $b && $c;
// $a === 1

?>

It is recommended to use the symbol operators, rather than the letter ones.

Short name Php/LogicalInLetters
Themes Analyze, Suggestions
ClearPHP no-letter-logical
Examples Cleverstyle, OpenConf

9.226. Logical To in_array

Multiples exclusive comparisons may be replaced by ‘in_array().

‘in_array() makes the alternatives more readable, especially when the number of alternatives is large. In fact, the list of alternative may even be set in a variable, and centralized for easier management.

Even two ‘or’ comparisons are slower than using a ‘in_array() call. More calls are even slower than just two. This is a micro-optimisation : speed gain is low, and marginal. Code centralisation is a more significant advantage.

<?php

// Set the list of alternative in a variable, property or constant.
$valid_values = array(1, 2, 3, 4);
if (in_array($a, $valid_values) ) {
    // doSomething()
}

if ($a == 1 || $a == 2 || $a == 3 || $a == 4) {
    // doSomething()
}

// in_array also works with strict comparisons
if (in_array($a, $valid_values, true) ) {
    // doSomething()
}

if ($a === 1 || $a === 2 || $a === 3 || $a === 4) {
    // doSomething()
}

?>

See also in_array().

Short name Performances/LogicalToInArray
Themes Analyze
Examples Zencart

9.227. Lone Blocks

Any grouped code without a commanding structure is useless.

Blocks are compulsory when defining a structure, such as a class or a function. They are most often used with flow control instructions, like if then or switch.

Blocks are also valid syntax that group several instructions together, though they have no effect at all, except confuse the reader. Most often, it is a ruin from a previous flow control instruction, whose condition was removed or commented. They should be removed.

<?php

    // Lone block
    //foreach($a as $b)
    {
        $b++;
    }
?>
Short name Structures/LoneBlock
Themes Analyze

9.228. Long Arguments

Long arguments should be put in variable, to preserve readability.

When literal arguments are too long, they ‘break the hosting structure by moving the next argument too far on the right. Whenever possible, long arguments should be set in a local variable to keep the readability.

<?php

// Now the call to foo() is easier to read.
$reallyBigNumber = <<<BIGNUMBER
123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
BIGNUMBER
foo($reallyBigNumber, 2, '12345678901234567890123456789012345678901234567890');

// where are the next arguments ?
foo('123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890', 2, '123456789012345678901234567890123456789012345678901234567890');

// This is still difficult to read
foo(<<<BIGNUMBER
123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
BIGNUMBER
, 2, '123456789012345678901234567890123456789012345678901234567890');

?>

Literal strings and heredoc strings, including variables, that are over 50 chars longs are reported here.

Short name Structures/LongArguments
Themes Analyze

9.229. Lost References

Either avoid references, or propagate them correctly.

When assigning a referenced variable with another reference, the initial reference is lost, while the intend was to transfer the content.

<?php

function foo(&$lostReference, &$keptReference)
{
    $c = 'c';

    // $lostReference was a reference, but now, it is another
    $lostReference =& $c;
    // $keptReference was a reference : now it contains the actual value
    $keptReference = $c;
}

$bar = 'bar';
$bar2 = 'bar';
foo($bar, $bar2);

//displays bar c, instead of bar bar
print $bar. ' '.$bar2;

?>

Do not reassign a reference with another reference. Assign new content to the reference to change its value.

Short name Variables/LostReferences
Themes Analyze

9.230. Magic Visibility

The class magic methods must have public visibility and cannot be static.

<?php

class foo{
    // magic method must bt public and non-static
    public static function '__clone($name) {    }

    // magic method can't be private
    private function '__get($name) {    }

    // magic method can't be protected
    private function '__set($name, $value) {    }

    // magic method can't be static
    public static function '__isset($name) {    }
}

?>

See also Magic methods.

Short name Classes/toStringPss
Themes CompatibilityPHP70

9.231. Make Global A Property

Calling global (or $GLOBALS) in methods is slower and less testable than setting the global to a property, and using this property.

Using properties is slightly faster than calling global or $GLOBALS, though the gain is not important.

Setting the property in the constructor (or in a factory), makes the class easier to test, as there is now a simple point of configuration.

<?php

// Wrong way
class fooBad {
    function x() {
        global $a;
        $a->do();
        // Or $GLOBALS['a']->do();
    }
}

class fooGood {
    private $bar = null;

    function '__construct() {
        global $bar;
        $this->bar = $bar;
        // Even better, do this via arguments
    }

    function x() {
        $this->a->do();
    }
}

?>
Short name Classes/MakeGlobalAProperty
Themes Analyze

9.232. Make One Call With Array

Avoid calling the same function several times by batching the calls with arrays.

Calling the same function to chain modifications tends to be slower than calling the same function with all the transformations at the same time. Some PHP functions accept scalars or arrays, and using the later is more efficient.

<?php

$string = 'abcdef';

//'str_replace() accepts arrays as arguments
$string = str_replace( ['a', 'b', 'c'],
                       ['A', 'B', 'C'],
                       $string);

// Too many calls to str_replace
$string = str_replace( 'a', 'A', $string);
$string = str_replace( 'b', 'B', $string);
$string = str_replace( 'c', 'C', $string);

// Too many nested calls to str_replace
$string = str_replace( 'a', 'A', str_replace( 'b', 'B', str_replace( 'c', 'C', $string)));

?>

Potential replacements :

Function Replacement
‘str_replace() ‘str_ireplace() ‘substr_replace() ‘preg_replace() ‘preg_replace_callback() ‘str_replace() ‘str_replace() ‘substr_replace() ‘preg_replace() ‘preg_replace_callback_array()
<?php
$subject = 'Aaaaaa Bbb';


//'preg_replace_callback_array() is better than multiple preg_replace_callback :
preg_replace_callback_array(
    [
        '~[a]+~i' => function ($match) {
            echo strlen($match[0]), ' matches for a found', PHP_EOL;
        },
        '~[b]+~i' => function ($match) {
            echo strlen($match[0]), ' matches for b found', PHP_EOL;
        }
    ],
    $subject
);

$result = preg_replace_callback('~[a]+~i', function ($match) {
            echo strlen($match[0]), ' matches for a found', PHP_EOL;
        }, $subject);

$result = preg_replace_callback('~[b]+~i', function ($match) {
            echo strlen($match[0]), ' matches for b found', PHP_EOL;
        }, $subject);

//'str_replace() accepts arrays as arguments
$string = str_replace( ['a', 'b', 'c'],
                       ['A', 'B', 'C'],
                       $string);

// Too many calls to str_replace
$string = str_replace( 'a', 'A');
$string = str_replace( 'b', 'B');
$string = str_replace( 'c', 'C');

?>
Short name Performances/MakeOneCall
Themes Performances

9.233. Malformed Octal

Those numbers starts with a 0, so they are using the PHP octal convention. Therefore, one can’t use 8 or 9 figures in those numbers, as they don’t belong to the octal base. The resulting number will be truncated at the first erroneous figure. For example, 090 is actually 0, and 02689 is actually 22.

<?php

// A long way to write 0 in PHP 5
$a = 0890;

// A fatal error since PHP 7

?>

Also, note that very large octal, usually with more than 21 figures, will be turned into a real number and undergo a reduction in precision.

See also Integers.

Short name Type/MalformedOctal
Themes CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56

9.234. Mark Callable

Create an attribute that guess what are the called function or methods, when possible.

Short name Functions/MarkCallable
Themes Analyze

9.235. Method Could Be Private Method

The following methods are never used outside their class of definition. Given the analyzed code, they could be set as private.

<?php

class foo {
    public function couldBePrivate() {}
    public function cantdBePrivate() {}

    function bar() {
        // couldBePrivate is used internally.
        $this->couldBePrivate();
    }
}

class foo2 extends foo {
    function bar2() {
        // cantdBePrivate is used in a child class.
        $this->cantdBePrivate();
    }
}

//couldBePrivate() is not used outside
$foo = new foo();

//cantdBePrivate is used outside the class
$foo->cantdBePrivate();

?>

Note that dynamic properties (such as $x->$y) are not taken into account.

Short name Classes/CouldBePrivateMethod
Themes Analyze

9.236. Method Used Below

Mark methods that are used in children classes.

<?php

class foo {
    // This method is used in children
    protected function protectedMethod() {}

    // This method is not used in children
    protected function localProtectedMethod() {}

    private function foobar() {
        // protectedMethod is used here, but defined in parent
        $this->localProtectedMethod();
    }
}

class foofoo extends foo {
    private function bar() {
        // protectedMethod is used here, but defined in parent
        $this->protectedMethod();
    }
}

?>

This doesn’t mark the current class, nor the (grand-)parent ones.

Short name Classes/MethodUsedBelow
Themes Analyze

9.237. Methodcall On New

It is possible to call a method right at object instanciation.

This syntax was added in PHP 5.4+. Before, this was not possible : the object had to be stored in a variable first.

<?php

// Data is collected
$data = data_source();

// Data is saved, but won't be reused from this databaseRow object. It may be ignored.
$result = (new databaseRow($data))->save();

// The actual result of the save() is collected and tested.
if ($result !== true) {
    processSaveError($data);
}

?>

This syntax is interesting when the object is not reused, and may be discarded

Short name Php/MethodCallOnNew
Themes CompatibilityPHP53

9.238. Mismatched Default Arguments

Arguments are relayed from one method to the other, and the arguments have different default values.

Although it is possible to have different default values, it is worth checking why this is actually the case.

<?php

function foo($a = null, $b = array() ) {
    // foo method calls directly bar.
    // When argument are provided, it's OK
    // When argument are omited, the default value is not the same as the next method
    bar($a, $b);
}

function bar($c = 1, $d = array() ) {

}

?>
Short name Functions/MismatchedDefaultArguments
Themes Analyze

9.239. Mismatched Ternary Alternatives

A ternary operator should yield the same type on both branches.

Ternary operator applies a condition, and yield two different results. Those results will then be processed by code that expects the same types. It is recommended to match the types on both branches of the ternary operator.

<?php

// $object may end up in a very unstable state
$object = ($type == 'Type') ? new $type() : null;

//same result are provided by both alternative, though process is very different
$result = ($type == 'Addition') ? $a + $b : $a * $b;

//Currently, this is omitted
$a = 1;
$result = empty($condition) ? $a : 'default value';
$result = empty($condition) ? $a : getDefaultValue();

?>
Short name Structures/MismatchedTernary
Themes Analyze, Suggestions

9.240. Mismatched Typehint

Relayed arguments don’t have the same typehint.

Typehint acts as a filter method. When an object is checked with a first class, and then checked again with a second distinct class, the whole process is always false : $a can’t be of two different classes at the same time.

<?php

// Foo() calls bar()
function foo(A $a, B $b) {
    bar($a, $b);
}

// $a is of A typehint in both methods, but
// $b is of B then BB typehing
function bar(A $a, BB $b) {

}

?>

Note : This analysis currently doesn’t check generalisation of classes : for example, when B is a child of BB, it is still reported as a mismatch.

Short name Functions/MismatchedTypehint
Themes Analyze

9.241. Missing Cases In Switch

It seems that some cases are missing in this switch structure.

When comparing two different ‘switch() structures, it appears that some cases are missing in one of them. The set of cases are almost identical, but one of the values are missing.

Switch() structures using strings as literals are compared in this analysis. When the discrepancy between two lists is below 25%, both switches are reported.

<?php

// This switch operates on a, b, c, d and default
switch($a) {
    case 'a': doSomethingA(); 'break 1;
    case 'b': doSomethingB(); 'break 1;
    case 'c': doSomethingC(); 'break 1;
    case 'd': doSomethingD(); 'break 1;
    default: doNothing();
}

// This switch operates on a, b, d and default
switch($o->p) {
    case 'a': doSomethingA(); 'break 1;
    case 'b': doSomethingB(); 'break 1;

    case 'd': doSomethingD(); 'break 1;
    default: doNothing();
}

?>

In the example, one may argue that the ‘c’ case is actually handled by the ‘default’ case. Otherwise, business logic may request that omission.

Short name Structures/MissingCases
Themes Analyze

9.242. Missing Include

The included files doesn’t exists in the repository. The inclusions target a files that doesn’t exist.

The analysis works with every type of inclusion : include, require, include_once and require_once. It also works with parenthesis when used as parameter delimiter.

The analysis doesn’t take into account include_path. This may yield false positives.

<?php

include 'non_existent.php';

// variables are not resolved. This won't be reported.
require ($path.'non_existent.php');

?>

Missing included files may lead to a Fatal error, a warning or other error later in the execution.

Short name Files/MissingInclude
Themes Analyze

9.243. Missing New ?

This functioncall looks like a class instantiation that is missing the new keyword.

Any function definition was found for that function, but a class with that name was. New is probably missing.

<?php

// Functioncall
$a = foo2();

// Class definition
class foo2 {}

?>
Short name Structures/MissingNew
Themes Analyze

9.244. Missing Parenthesis

Add parenthesis to those expression to prevent bugs.

<?php

// Missing some parenthesis!!
if (!$a 'instanceof Stdclass) {
    print Not\n;
} else {
    print Is\n;
}

// Could this addition be actually
$c = -$a + $b;

// This one ?
$c = -($a + $b);

?>

See also Operators Precedence.

Short name Structures/MissingParenthesis
Themes Analyze

9.245. Mistaken Concatenation

A unexpected structure is built for initialization. It may be a typo that creates an unwanted expression.

<?php

// This 'cd' is unexpected. Isn't it 'c', 'd' ?
$array = array('a', 'b', 'c'. 'd');
$array = array('a', 'b', 'c', 'd');

// This 4.5 is unexpected. Isn't it 4, 5 ?
$array = array(1, 2, 3, 4.5);
$array = array(1, 2, 3, 4, 5);

?>
Short name Arrays/MistakenConcatenation
Themes Analyze

9.246. Mixed Concat And Interpolation

Mixed usage of concatenation and string interpolation is error prone. It is harder to read, and leads to overlooking the concatenation or the interpolation.

<?php

// Concatenation string
$a = $b . 'c' . $d;

// Interpolation strings
$a = {$b}c{$d};   // regular form
$a = {$b}c$d;     // irregular form

// Mixed Concatenation and Interpolation string
$a = {$b}c . $d;
$a = $b . c$d;
$a = $b . c{$d};

// Mixed Concatenation and Interpolation string with constant
$a = {$b}c . CONSTANT;

?>

Fixing this issue has no impact on the output. It makes code less error prone.

There are some situations where using concatenation are compulsory : when using a constant, calling a function, running a complex expression or make use of the escape sequence. You may also consider pushing the storing of such expression in a local variable.

Short name Structures/MixedConcatInterpolation
Themes Coding Conventions, Analyze

9.247. Mixed Keys Arrays

Avoid mixing constants and literals in array keys.

When defining default values in arrays, it is recommended to avoid mixing constants and literals, as PHP may mistake them and overwrite the previous with the latter.

Either switch to a newer version of PHP (5.5 or newer), or make sure the resulting array is the one you expect. If not, reorder the definitions.

<?php

const ONE = 1;

$a = [ 1   => 2,
       ONE => 3];

?>
Short name Arrays/MixedKeys
Themes CompatibilityPHP53, CompatibilityPHP54

9.248. Mkdir Default

‘mkdir() gives universal access to created folders, by default. It is recommended to gives a more limited set of rights (0755, 0700), or to explicitely set the rights to 0777.

<?php

// By default, this dir is 777
mkdir('/path/to/dir');

// Explicitely, this is wanted. It may also be audited easily
mkdir('/path/to/dir', 0777);

// This dir is limited to the current user.
mkdir('/path/to/dir', 0700);

?>

See also Why 777 Folder Permissions are a Security Risk.

Short name Security/MkdirDefault
Themes Security

9.249. Modernize Empty With Expression

‘empty() accept expressions since PHP 5.5. There is no need to store the expression in a variable before testing, unless it is reused later.

<?php

// PHP 5.5+ 'empty() usage
if (empty(strtolower($b . $c))) {
    doSomethingWithoutA();
}

// Compatible 'empty() usage
$a = strtolower($b . $c);
if (empty($a)) {
    doSomethingWithoutA();
}

// $a2 is reused, storage is legit
$a2 = strtolower($b . $c);
if (empty($a2)) {
    doSomething();
} else {
    echo $a2;
}

?>

See also empty().

Short name Structures/ModernEmpty
Themes Analyze

9.250. Multiple Alias Definitions

Some aliases are representing differents classes across the repository. This leads to potential confusion.

Across an application, it is recommended to use the same namespace for one alias. Failing to do this lead to the same keyword to represent different values in different files, with different behavior. Those are hard to find bugs.

<?php

namespace A {
    use d\d; // aka D
}

// Those are usually in different files, rather than just different namespaces.

namespace B {
    use b\c as D; // also D. This could be named something else
}

?>
Short name Namespaces/MultipleAliasDefinitions
Themes Analyze

9.251. Multiple Alias Definitions Per File

Avoid aliasing the same name with different aliases. This leads to confusion.

<?php

// first occurrence
use name\space\ClasseName;

// when this happens, several other uses are mentionned

// name\space\ClasseName has now two names
use name\space\ClasseName as anotherName;

?>

See also Multiple Alias Definitions.

Short name Namespaces/MultipleAliasDefinitionPerFile
Themes Analyze

9.252. Multiple Class Declarations

It is possible to declare several times the same class in the code. PHP will not mention it until execution time, since declarations may be conditional.

<?php

$a = 1;

// Conditional declaration
if ($a == 1) {
    class foo {
        function method() { echo 'class 1';}
    }
} else {
    class foo {
        function method() { echo 'class 2';}
    }
}

(new foo())->method();
?>

It is recommended to avoid declaring several times the same class in the code. The best practice is to separate them with namespaces, they are for here for that purpose. In case those two classes are to be used interchangeably, the best is to use an abstract class or an interface.

Short name Classes/MultipleDeclarations
Themes Analyze

9.253. Multiple Classes In One File

It is regarded as a bad practice to cram more than one class per file. This is usually done to make life of __autoload() easier.

It is often difficult to find class foo in the bar.php file. This is also the case for interfaces and traits.

<?php

// three classes in the same file
class foo {}
class bar {}
class foobar{}

?>

One good reason to have multiple classes in one file is to reduce include time by providing everything into one nice include.

See also Is it a bad practice to have multiple classes in the same file?

Short name Classes/MultipleClassesInFile
Themes Coding Conventions

9.254. Multiple Constant Definition

Some constants are defined several times in your code. This will lead to a fatal error, if they are defined during the same execution.

Multiple definitions may happens at boostrap, when the application code is collecting information about the current environnement. It may also happen at inclusion time, which one set of constant being loaded, while other definition are not, avoiding conflict. Both are false positive.

<?php

// OS is defined twice.
if (PHP_OS == 'Windows') {
    define('OS', 'Win');
} else {
    define('OS', 'Other');
}

?>
Short name Constants/MultipleConstantDefinition
Themes Analyze

9.255. Multiple Definition Of The Same Argument

A method’s signature is holding twice (or more) the same argument. For example, function x ($a, $a) { … }.

This is accepted as is by PHP 5, and the last parameter’s value will be assigned to the variable. PHP 7.0 and more recent has dropped this feature, and reports a fatal error when linting the code.

<?php
  function x ($a, $a) { print $a; };
  x(1,2); => display 2
?>

However, this is not common programming practise : all arguments should be named differently.

See also Prepare for PHP 7 error messages (part 3).

Short name Functions/MultipleSameArguments
Themes CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56
ClearPHP all-unique-arguments

9.256. Multiple Exceptions Catch()

Starting with PHP 7.1, it is possible to have several distinct exceptions class caught by the same catch, preventing code repetition.

<?php

// PHP 7.1 and more recent
try {
    throw new someException();
} catch (Single $s) {
    doSomething();
} catch (oneType | anotherType $s) {
    processIdentically();
} finally {

}

// PHP 7.0 and older
try {
    throw new someException();
} catch (Single $s) {
    doSomething();
} catch (oneType $s) {
    processIdentically();
} catch (anotherType $s) {
    processIdentically();
} finally {

}

?>

This is a backward incompabitible feature of PHP 7.1.

Short name Exceptions/MultipleCatch
Themes CompatibilityPHP53, CompatibilityPHP70, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56

9.257. Multiple Identical Trait Or Interface

There is no need to use the same trait, or implements the same interface more than once.

Up to PHP 7.1 (at least), this doesn’t raise any warning. Traits are only imported once, and interfaces may be implemented as many times as wanted.

<?php

class foo {
    use t3,t3,t3;
}

class bar implements i,i,i {

}

?>
Short name Classes/MultipleTraitOrInterface
Themes Analyze

9.258. Multiple Index Definition

Indexes that are defined multiple times in the same array.

<?php
    // Multiple identical keys
    $x = array(1 => 2,
               2 => 3,
               1 => 3);

    // Multiple identical keys (sneaky version)
    $x = array(1 => 2,
               1.1 => 3,
               true => 4);

    // Multiple identical keys (automated version)
    $x = array(1 => 2,
               3,        // This will be index 2
               2 => 4);  // this index is overwritten
?>

They are indeed overwriting each other. This is most probably a typo.

Short name Arrays/MultipleIdenticalKeys
Themes Analyze

9.259. Multiple Type Variable

Avoid using the same variable with different types of data.

It is recommended to use different names for differently typed data, while processing them. This prevents errors where one believe the variable holds the former type, while it has already been cast to the later.

Incrementing variables, with math operations or concatenation, is OK : the content changes, but not the type. And casting the variable without storing it in itself is OK.

<?php

// $x is an array
$x = range('a', 'z');
// $x is now a string
$x = join('', $x);
$c = count($x); // $x is not an array anymore


// $letters is an array
$letters = range('a', 'z');
// $alphabet is a string
$alphabet = join('', $letters);

// Here, $letters is cast by PHP, but the variable is changed.
if ($letters) {
    $count = count($letters); // $letters is still an array
}

?>
Short name Structures/MultipleTypeVariable
Themes Analyze

9.260. Multiples Identical Case

Some cases are defined multiple times, but only one will be processed. Check the list of cases, and remove the extra one.

Exakat tries to find the value of the case as much as possible, and ignore any dynamic cases (using variables).

<?php

const A = 1;

case ($x) {
    case 1 :
        'break;
    case true:    // This is a duplicate of the previous
        'break;
    case 1 + 0:   // This is a duplicate of the previous
        'break;
    case 1.0 :    // This is a duplicate of the previous
        'break;
    case A :      // The A constant is actually 1
        'break;
    case $y  :    // This is not reported.
        'break;
    default:

}
?>
Short name Structures/MultipleDefinedCase
Themes Analyze
ClearPHP no-duplicate-case

9.261. Multiply By One

Multiplying by 1 is useless.

If it is used to type cast a value to number, then casting (integer) or (real) is clearer. This behavior may change with PHP 7.1, which has unified the behavior of all hidden casts.

<?php

// Still the same value than $m, but now cast to integer or real
$m = $m * 1;

// Still the same value than $m, but now cast to integer or real
$n *= 1;

// make typecasting clear, and merge it with the producing call.
$n = (int) $n;

?>
Short name Structures/MultiplyByOne
Themes Analyze
ClearPHP no-useless-math

9.262. Must Return Methods

The following methods are expected to return a value that will be used later. Without return, they are useless.

Methods that must return are : ‘__get(), ‘__isset(), ‘__sleep(), ‘__toString(), ‘__set_state(), ‘__invoke(), ‘__debugInfo(). Methods that may not return, but are often expected to : ‘__call(), ‘__callStatic().

<?php

class foo {
    public function '__isset($a) {
        // returning something useful
        return 'isset($this->$var[$a]);
    }

    public function '__get($a) {
        $this->$a++;
        // not returning...
    }

    public function '__call($name, $args) {
        $this->$name(...$args);
        // not returning anything, but that's OK
    }

}
?>
Short name Functions/MustReturn
Themes Analyze

9.263. Negative Power

The power operator ‘** has higher precedence than the sign operators + and -.

This means that -2 ‘** 2 == -4. It is in fact, -(2 ‘** 2).

When using negative power, it is clearer to add parenthesis or to use the ‘pow() function, which has no such ambiguity :

<?php

// -2 to the power of 2 (a square)
pow(-2, 2) == 4;

// minus 2 to the power of 2 (a negative square)
-2 '** 2 == -(2 '** 2) == 4;

?>
Short name Structures/NegativePow
Themes Analyze

9.264. Nested Ifthen

Three levels of ifthen is too much. The method should be split into smaller functions.

<?php

function foo($a, $b) {
    if ($a == 1) {
        // Second level, possibly too much already
        if ($b == 2) {

        }
    }
}

function bar($a, $b, $c) {
    if ($a == 1) {
        // Second level.
        if ($b == 2) {
            // Third level level.
            if ($c == 3) {
                // Too much
            }
        }
    }
}

?>
Short name Structures/NestedIfthen
Themes Analyze

9.265. Nested Ternary

Ternary operators should not be nested too deep.

They are a convenient instruction to apply some condition, and avoid a if() structure. It works best when it is simple, like in a one liner.

However, ternary operators tends to make the syntax very difficult to read when they are nested. It is then recommended to use an if() structure, and make the whole code readable.

<?php

// Simple ternary expression
echo ($a == 1 ? $b : $c) ;

// Nested ternary expressions
echo ($a === 1 ? $d === 2 ? $b : $d : $d === 3 ? $e : $c) ;
echo ($a === 1 ? $d === 2 ? $f ===4 ? $g : $h : $d : $d === 3 ? $e : $i === 5 ? $j : $k) ;

//Previous expressions, written as a if / Then expression
if ($a === 1) {
    if ($d === 2) {
        echo $b;
    } else {
        echo $d;
    }
} else {
    if ($d === 3) {
        echo $e;
    } else {
        echo $c;
    }
}

if ($a === 1) {
    if ($d === 2) {
        if ($f === 4) {
            echo $g;
        } else {
            echo $h;
        }
    } else {
        echo $d;
    }
} else {
    if ($d === 3) {
        echo $e;
    } else {
        if ($i === 5) {
            echo $j;
        } else {
            echo $k;
        }
    }
}

?>
Short name Structures/NestedTernary
Themes Analyze
ClearPHP no-nested-ternary

9.266. Never Used Parameter

When a parameter is never used at calltime, it may be turned into a local variable.

It seems that the parameter was set up initially, but never found its practical usage. It is never mentionned, and always fall back on its default value.

Parameter without a default value are reported by PHP, and are usually always filled.

<?php

// $b may be turned into a local var, it is unused
function foo($a, $b = 1) {
    return $a + $b;
}

// whenever foo is called, the 2nd arg is not mentionned
foo($a);
foo(3);
foo('a');
foo($c);

?>
Short name Functions/NeverUsedParameter
Themes Analyze, Suggestions

9.267. Never Used Properties

Properties that are never used. They are defined, but never actually used.

<?php

class foo {
    public $usedProperty = 1;

    // Never used anywhere
    public $unusedProperty = 2;

    function bar() {
        // Used internally
        ++$this->usedProperty;
    }
}

class foo2  extends foo {
    function bar2() {
        // Used in child class
        ++$this->usedProperty;
    }
}

// Used externally
++$this->usedProperty;

?>
Short name Classes/PropertyNeverUsed
Themes Analyze

9.268. New Constants In PHP 7.2

The following constants are now native in PHP 7.2. It is advised to avoid using such names for constant before moving to this new version.

  • PHP_OS_FAMILY
  • PHP_FLOAT_DIG
  • PHP_FLOAT_EPSILON
  • PHP_FLOAT_MAX
  • PHP_FLOAT_MIN
  • SQLITE3_DETERMINISTIC
  • CURLSSLOPT_NO_REVOKE
  • CURLOPT_DEFAULT_PROTOCOL
  • CURLOPT_STREAM_WEIGHT
  • CURLMOPT_PUSHFUNCTION
  • CURL_PUSH_OK
  • CURL_PUSH_DENY
  • CURL_HTTP_VERSION_2TLS
  • CURLOPT_TFTP_NO_OPTIONS
  • CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE
  • CURLOPT_CONNECT_TO
  • CURLOPT_TCP_FASTOPEN
  • DNS_CAA

Note : PHP 7.2 is not out yet (2017-04-10). This list is currently temporary and may undergo changes until the final version is out.

Short name Php/Php72NewConstants
Themes CompatibilityPHP72

9.269. New Functions In PHP 5.4

PHP introduced new functions in PHP 5.4. If you have already defined functions with such names, you will get a conflict when trying to upgrade. It is advised to change those functions’ name.

Short name Php/Php54NewFunctions
Themes CompatibilityPHP53

9.270. New Functions In PHP 5.5

PHP introduced new functions in PHP 5.5. If you have already defined functions with such names, you will get a conflict when trying to upgrade. It is advised to change those functions’ name.

Short name Php/Php55NewFunctions
Themes CompatibilityPHP53, CompatibilityPHP54

9.271. New Functions In PHP 5.6

PHP introduced new functions in PHP 5.6. If you have already defined functions with such names, you will get a conflict when trying to upgrade. It is advised to change those functions’ name.

Short name Php/Php56NewFunctions
Themes CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55

9.272. New Functions In PHP 7.0

The following functions are now native functions in PHP 7.0. It is advised to change them before moving to this new version.

  • get_resources
  • gc_mem_caches
  • preg_replace_callback_array
  • posix_setrlimit
  • random_bytes
  • random_int
  • intdiv
  • error_clear_last
Short name Php/Php70NewFunctions
Themes CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56

9.273. New Functions In PHP 7.1

The following functions are now native functions in PHP 7.1. It is advised to change them before moving to this new version.

  • curl_share_strerror()
  • curl_multi_errno()
  • curl_share_errno()
  • mb_ord()
  • mb_chr()
  • mb_scrub()
  • is_iterable()
Short name Php/Php71NewFunctions
Themes CompatibilityPHP71

9.274. New Functions In PHP 7.2

The following functions are now native functions in PHP 7.2. It is advised to change them before moving to this new version.

  • mb_ord()
  • mb_chr()
  • mb_scrub()
  • stream_isatty()
  • ‘proc_nice() (Windows only)
Short name Php/Php72NewFunctions
Themes CompatibilityPHP72

9.275. New Functions In PHP 7.3

This documentation is still empty.

The following functions are now native functions in PHP 7.3. It is advised to change them before moving to this new version.

  • net_get_interfaces( )
Short name Php/Php73NewFunctions
Themes CompatibilityPHP53, CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP72, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56

9.276. Next Month Trap

Avoid using +1 month with strtotime().

strtotime() calculates the next month by incrementing the month number. For day number that do not exist from one month to the next, strtotime() fixes them by setting them in the next-next month.

This happens to January, March, May, July, August and October. January is also vulnerable for 29 (not every year), 30 and 31.

Avoid using ‘+1 month’, and rely on ‘first day of next month’ or ‘last day of next month’ to extract the next month’s name.

<?php

// Base date is October 31 => 10/31
// +1 month adds +1 to 10 => 11/31
// Since November 31rst doesn't exists, it is corrected to 12/01.
echo date('F', strtotime('+1 month',mktime(0,0,0,$i,31,2017))).PHP_EOL;

// Base date is October 31 => 10/31
echo date('F', strtotime('first day of next month',mktime(0,0,0,$i,31,2017))).PHP_EOL;

?>

See also It is the 31st again.

Short name Structures/NextMonthTrap
Themes Analyze
Examples Contao, Edusoho

9.277. No Boolean As Default

Default values should always be set up with constants.

Class constants or constants improve readability when calling the methods.

<?php

const CASE_INSENSITIVE = true;
const CASE_SENSITIVE = false;

function foo($case_insensitive = true) {
    // doSomething()
}

// Readable code
foo(CASE_INSENSITIVE);
foo(CASE_SENSITIVE);


// unreadable code  : is true case insensitive or case sensitive ?
foo(true);
foo(false);

?>
Short name Functions/NoBooleanAsDefault
Themes Analyze

9.278. No Choice

A conditional structure is being used, but both alternatives are the same, leading to the illusion of choice.

Either the condition is useless, and may be removed, or the alternatives need to be distinguished.

<?php

if ($condition == 2) {
    doSomething();
} else {
    doSomething();
}

$condition == 2 ?     doSomething() :     doSomething();

?>
Short name Structures/NoChoice
Themes Analyze
Examples NextCloud, Zencart

9.279. No Class As Typehint

Avoid using whole classes as typehint. Always use interfaces, so that you may use different classes, or versions of classes.

<?php

class X {
    function foo() {}
}

interface i {
    function foo();
}

// X is a class : any update in the code requires changing / subclassing X or the rest of the code.
function bar(X $x) {
    $x->foo();
}

// I is an interface : X may implements this interface without refactoring and pass
// later, newer versions of X may get another name, but still implement I, and still pass
function bar2(I $x) {
    $x->foo();
}

?>

See also Type hinting for interfaces.

Short name Functions/NoClassAsTypehint
Themes Analyze

9.280. No Class In Global

Avoid defining structures in Global namespace. Always prefer using a namespace. This will come handy later, either when publishing the code, or when importing a library, or even if PHP reclaims that name.

<?php

// Code prepared for later
namespace Foo {
    class Bar {}
}

// Code that may conflict with other names.
namespace {
    class Bar {}
}

?>
Short name Php/NoClassInGlobal
Themes Analyze

9.281. No Count With 0

Comparing ‘count() and strlen() to 0 is a waste of resources. There are three distinct situations situations.

When comparing ‘count() with 0, with ===, ==, !==, !=, it is more efficient to use ‘empty(). Empty() is a language constructs that checks if a value is present, while ‘count() actually load the number of element.

<?php

// Checking if an array is empty
if (count($array) == 0) {
    // doSomething();
}
// This may be replaced with
if (empty($array)) {
    // doSomething();
}

?>

When comparing ‘count() strictly with 0 (>) it is more efficient to use !(‘empty())

<?php

// Checking if an array is empty
if (count($array) > 0) {
    // doSomething();
}
// This may be replaced with
if (!empty($array)) {
    // doSomething();
}

Of course comparing 'count() with negative values, or with >= is useless.

<?php

// Checking if an array is empty
if (count($array) < 0) {
    // This never happens
    // doSomething();
}

?>

Comparing ‘count() and strlen() with other values than 0 cannot be replaced with a comparison with ‘empty().

Note that this is a micro-optimisation : since PHP keeps track of the number of elements in arrays (or number of chars in strings), the total computing time of both operations is often lower than a ms. However, both functions tends to be heavily used, and may even be used inside loops.

Short name Performances/NotCountNull
Themes Performances
Examples WordPress

9.282. No Direct Call To Magic Method

PHP magic methods, such as ‘__get(), ‘__set(), … are supposed to be used in an object environnement, and not with direct call.

For example,

<?php
  print $x->'__get('a');

//should be written
  print $x->a;
?>

Accessing those methods in a static way is also discouraged.

Short name Classes/DirectCallToMagicMethod
Themes Analyze

9.283. No Direct Input To Wpdb

Avoid using incoming variables when building SQL queries with $wpdb->prepare().

(This is quoted directly from Anthony Ferrera blog, link below). In general however, go through and remove all user input from the $query side of ->prepare(). NEVER pass user input to the query side. Meaning, never do this (in any form):

<?php
  $where = $wpdb->prepare(' WHERE foo = %s', $_GET['data']);
  $query = $wpdb->prepare('SELECT * FROM something $where LIMIT %d, %d', 1, 2);
?>

This is known as ‘double-preparing’ and is not a good design. (End of quote).

See also https://blog.ircmaxell.com/2017/10/disclosure-wordpress-wpdb-sql-injection-technical.html.

Short name Wordpress/NoDirectInputToWpdb
Themes Wordpress

9.284. No Direct Usage

The results of the following functions shouldn’t be used directly, but checked first.

For example, ‘glob() returns an array, unless some error happens, in which case it returns a boolean (false). In such case, however rare it is, plugging ‘glob() directly in a ‘foreach() loops will yield errors.

<?php
    // Used without check :
    foreach(glob('.') as $file) { /* do Something */ }.

    // Used without check :
    $files = glob('.');
    if (!is_array($files)) {
        foreach($files as $file) { /* do Something */ }.
    }
?>
Short name Structures/NoDirectUsage
Themes Analyze

9.285. No Echo In Route Callable

Avoid using echo(), ‘print() or any printable PHP within the route callable method.

echo() works, it is prevents the code from setting any status code. This leads to confusion when the code return the content, but fail to set the right HTTP codes.

Slim 4.0 will require to only use the return method : the route callable is required to return a response.

<?php
$app = new Slim\App();

// This works as expected, with or without status
$app->get('/', function ($request, $response, $args) {
    return new MyResponseInterface ('content');
});

// This works, but only on surface
$app->get('/', function ($request, $response, $args) {
    echo 'content';
});

?>

See PSR7 and PSR 7 and Value Objects.

Short name Slim/NoEchoInRouteCallable
Themes Slim

9.286. No Echo Outside View

Views are the place where data is displayed to the browser. There should not be any other display of information from anywhere else in the code.

In a view.phtml file : .. code-block:: php

<?php

echo $this->view;

?>

In a controller.php file :

<?php

use Zend\Mvc\Controller\AbstractActionController;

class myController extends AbstractActionController
{

    public function indexAction() {
        if ($wrong) {
            echo $errorMessage;
        }

        $view = new ViewModel(array(
            'message' => 'Hello world',
        ));
        $view->setTemplate('view.phtml');
        return $view;
    }
}

?>
Short name ZendF/NoEchoOutsideView
Themes ZendFramework

9.287. No Empty Regex

PHP regex don’t accept empty regex, nor regex with alphanumeric delimiter.

Most of those errors happen at execution time, when the regex is build dynamically, but still may end empty. At compile time, such error are made when the code is not tested before commit.

<?php

// No empty regex
preg_match('', $string, $r);

// Delimiter must be non-alphanumerical
preg_replace('1abc1', $string, $r);

// Delimiter must be non-alphanumerical
preg_replace('1'.$regex.'1', $string, $r);

?>

See also PCRE and Delimiters.

Short name Structures/NoEmptyRegex
Themes Analyze

9.288. No Global Modification

Avoid modifying directly Wordpress global variables.

It is recommended to use the function API instead.

<?php

my_hook() {
    // Avoid changing those variables, as Wordpress handles them
    $GLOBALS['is_safari'] = true;
}

?>

See also Global Variables

Short name Wordpress/NoGlobalModification
Themes Wordpress

9.289. No Hardcoded Hash

Hash should never be hardcoded.

Hashes may be MD5, SHA1, SHA512, Bcrypt or any other. Such values must be easily changed, for security reasons, and the source code is not the safest place to hide it.

<?php

    // Those strings may be sha512 hashes.
    // it is recomemdned to check if they are static or should be put into configuration
    $init512 = array( // initial values for SHA512
        '6a09e667f3bcc908', 'bb67ae8584caa73b', '3c6ef372fe94f82b', 'a54ff53a5f1d36f1',
    );

?>
Short name Structures/NoHardcodedHash
Themes Analyze, Security

9.290. No Hardcoded Ip

Do not leave hard coded IP in your code.

It is recommended to move such configuration in external files or databases, for each update. This may also come handy when testing.

<?php

// This IPv4 is hardcoded.
$ip = '183.207.224.50';
// This IPv6 is hardcoded.
$ip = '2001:0db8:85a3:0000:0000:8a2e:0370:7334';

// This looks like an IP
$thisIsNotAnIP = '213.187.99.50';
$thisIsNotAnIP = '2133:1387:9393:5330';

?>

127.0.0.1, ::1 and ::0 are omitted, and not considered as a violation.

Short name Structures/NoHardcodedIp
Themes Analyze, Security

9.291. No Hardcoded Path

It is not recommended to have literals when accessing files.

Either use ‘__FILE__ and ‘__DIR__ to make the path relative to the current file; use a DOC_ROOT as a configuration constant that will allow you to move your script later or rely on functions likes ‘sys_get_temp_dir(), to reach special folders.

<?php

    // This depends on the current executed script
    file_get_contents('token.txt');

    // Exotic protocols are ignored
    file_get_contents('jackalope://file.txt');

    // Some protocols are ignored : http, https, ftp, ssh2, php (with memory)
    file_get_contents('http://www.php.net/');
    file_get_contents('php://memory/');

    // 'glob() with special chars * and ? are not reported
    glob('./*/foo/bar?.txt');
    // 'glob() without special chars * and ? are reported
    glob('/foo/bar/');

?>
Short name Structures/NoHardcodedPath
Themes Analyze
ClearPHP no-hardcoded-path

9.292. No Hardcoded Port

When connecting to a remove server, port is an important information. It is recommended to make this configurable (with constant or configuration), to as to be able to change this value without changing the code.

<?php

    // Both configurable IP and hostname
    $connection = ssh2_connect($_ENV['SSH_HOST'], $_ENV['SSH_PORT'], $methods, $callbacks);

    // Both hardcoded IP and hostname
    $connection = ssh2_connect('shell.example.com', 22, $methods, $callbacks);

    if (!$connection) 'die('Connection failed');
?>
Short name Structures/NoHardcodedPort
Themes Analyze, Security

9.293. No Isset With Empty

Empty() actually does the job of Isset() too.

From the manual : No warning is generated if the variable does not exist. That means ‘empty() is essentially the concise equivalent to !`’isset( <http://www.php.net/isset>`_$var) || $var == false.

<?php


// Enough tests
if (i!empty($a)) {
    doSomething();
}

// Too many tests
if ('isset($a) && !empty($a)) {
    doSomething();
}

?>
Short name Structures/NoIssetWithEmpty
Themes Analyze

9.294. No List With String

list() can’t be used anymore to access particular offset in a string. This should be done with substr() or $string[$offset] syntax.

<?php

$x = 'abc';
list($a, $b, $c) = $x;

//list($a, $b, $c) = 'abc'; Never works

print $c;
// PHP 5.6- displays 'c'
// PHP 7.0+ displays nothing

?>

See also PHP 7.0 Backward incompatible changes : list() can no longer unpack string variables.

Short name Php/NoListWithString
Themes CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56

9.295. No Magic With Array

Magic method __get() doesn’t work for array syntax.

When overloading properties, they can only be used for scalar values, excluding arrays. Under the hood, PHP uses __get() to reach for the name of the property, and doesn’t recognize the following index as an array. It yields an error : Indirect modification of overloaded property.

<?php

class c {
    private $a;
    private $o = array();

    function '__get($name) {
        return $this->o[$name];
    }

    function foo() {
        // property b doesn't exists
        $this->b['a'] = 3;

        print_r($this);
    }

    // This method has no impact on the issue
    function '__set($name, $value) {
        $this->o[$name] = $value;
    }
}

$c = new c();
$c->foo();

?>

This is not reported by linting.

In this analysis, only properties that are found to be magic are reported. For example, using the b property outside the class scope is not reported, as it would yield too many false-positives.

See also Overload.

Short name Classes/NoMagicWithArray
Themes Analyze

9.296. No Need For Else

Else is not needed when the Then ends with a ‘break. A ‘break may be the following keywords : ‘break, ‘continue, return, goto. Any of these send the execution somewhere in the code. The else block is then executed as the main sequence, only if the condition fails.

<?php

function foo() {
    // Else may be in the main sequence.
    if ($a1) {
        return $a1;
    } else {
        $a++;
    }

    // Same as above, but negate the condition : if (!$a2) { return $a2; }
    if ($a2) {
        $a++;
    } else {
        return $a2;
    }

    // This is OK
    if ($a3) {
        return;
    }

    // This has no 'break
    if ($a4) {
        $a++;
    } else {
        $b++;
    }

    // This has no else
    if ($a5) {
        $a++;
    }
}
?>

See also Object Calisthenics, rule # 2.

Short name Structures/NoNeedForElse
Themes Analyze

9.297. No Net For Xml Load

Simplexml and ext/DOM load all external entities on the web, by default. This is dangerous, when loading unknown XML code.:

<!DOCTYPE replace [<!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=index.php"> ]>
<replace>&xxe;</replace>

Here, PHP tries to load the XML file, find the entity, then solves the entity by encoding a file called ‘index.php’. The source code of the file is not used as data in the xml file.

See also XML External Entity,
XML External Entity (XXE) Processing and Detecting and exploiting XXE in SAML Interfaces.
Short name Security/NoNetForXmlLoad
Themes Security

9.298. No Parenthesis For Language Construct

Some PHP language constructs, such are include, print, echo don’t need parenthesis. They cope with parenthesis, but it is may lead to strange situations.

<?php

// This is an attempt to load 'foo.inc', or kill the script
include('foo.inc') or 'die();
// in fact, this is read by PHP as : include 1
// include  'foo.inc' or 'die();

?>

It it better to avoid using parenthesis with echo, print, return, throw, yield, yield from, include, require, include_once, require_once.

See also include.

Short name Structures/NoParenthesisForLanguageConstruct
Themes Analyze, Suggestions
ClearPHP no-parenthesis-for-language-construct

9.299. No Plus One

Incrementing a variable should be done with the ++ or – operators. Any other way, may be avoided.

<?php

// Best way to increment
++$x; --$y;

// Second best way to increment, if the current value is needed :
echo $x++, $y--;

// Good but slow
$x += 1;
$x -= -1;

$y += -1;
$y -= 1;

// even slower
$x = $x + 1;
$y = $y - 1;

?>
Short name Structures/PlusEgalOne
Themes Coding Conventions

9.300. No Public Access

The properties below are declared with public access, but are never used publicly. They can be made protected or private.

<?php

class foo {
    public $bar = 1;            // Public, and used in public space
    public $neverInPublic = 3;  // Public, but never used in outside the class

    function bar() {
        $neverInPublic++;
    }
}

$x = new foo();
$x->bar = 3;
$x->bar();

?>
Short name Classes/NoPublicAccess
Themes Analyze

9.301. No Real Comparison

Avoid comparing decimal numbers with ==, ===, !==, !=. Real numbers have an error margin which is random, and makes it very difficult to match even if the compared value is a literal.

PHP uses an internal representation in base 2 : any number difficult to represent with this base (like 0.1 or 0.7) will have a margin of error.

<?php

$a = 1/7;
$b = 2.0;

// 7 * $a is a real, not an integer
var_dump( 7 * $a === 1);

// rounding error leads to wrong comparison
var_dump( (0.1 + 0.7) * 10 == 8);
// although
var_dump( (0.1 + 0.7) * 10);
// displays 8

// precision formula to use with reals. Adapt 0.0001 to your precision needs
var_dump( abs(((0.1 + 0.7) * 10) - 8) < 0.0001);

?>

Use precision formulas with ‘abs() to approximate values with a given precision, or avoid reals altogether.

See also Floating point numbers.

Short name Type/NoRealComparison
Themes Analyze
ClearPHP no-real-comparison

9.302. No Reference On Left Side

Do not use references as the right element in an assignation.

<?php

$b = 2;
$c = 3;

$a = &$b + $c;
// $a === 2 === $b;

$a = $b + $c;
// $a === 5

?>

This is the case for most situations : addition, multiplication, bitshift, logical, power, concatenation. Note that PHP won’t compile the code if the operator is a short operator (+=, .=, etc.), nor if the & is on the right side of the operator.

Short name Structures/NoReferenceOnLeft
Themes Analyze

9.303. No Return Or Throw In Finally

Avoid using return and throw in a finally block. Both command will interrupt the processing of the try catch block, and any exception that was emitted will not be processed. This leads to unprocessed exceptions, leaving the application in an unstable state.

Note that PHP prevents the usage of goto, ‘break and ‘continue within the finally block at linting phase. This is categorized as a Security problem.

<?php
function foo() {
        try {
            // Exception is thrown here
            throw new \Exception();
        } catch (Exception $e) {
            // This is executed AFTER finally
            return 'Exception';
        } finally {
            // This is executed BEFORE catch
            return 'Finally';
        }
    }
}

// Displays 'Finally'. No exception
echo foo();

function bar() {
        try {
            // Exception is thrown here
            throw new \Exception();
        } catch (Exception $e) {
            // Process the exception.
            return 'Exception';
        } finally {
            // clean the current situation
            // Keep running the current function
        }
        return 'Finally';
    }
}

// Displays 'Exception', with processed Exception
echo bar();

?>

See also Return Inside Finally Block.

Short name Structures/NoReturnInFinally
Themes Security

9.304. No Return Used

The return value of the following functions are never used. The return argument may be dropped from the code, as it is dead code.

This analysis supports functions and static methods, when a definition may be found. It doesn’t support method calls.

<?php

function foo($a = 1;) { return 1; }
foo();
foo();
foo();
foo();
foo();
foo();

// This function doesn't return anything.
function foo2() { }

// The following function are used in an expression, thus the return is important
function foo3() {  return 1;}
function foo4() {  return 1;}
function foo5() {  return 1;}

foo3() + 1;
$a = foo4();
foo(foo5());

?>
Short name Functions/NoReturnUsed
Themes Analyze, Suggestions

9.305. No Self Referencing Constant

It is not possible to use ‘self’ when defining a constant in a class. It will yield a fatal error at runtime.

<?php
    class a {
        const C1 = 1;
        const C2 = self::C1;
        const C3 = a::C3;
    }
?>

The code needs to reference the full class’s name to do so, without using the current class’s name.

<?php
    class a {
        const C1 = 1;
        const C2 = a::C1;
    }
?>
Short name Classes/NoSelfReferencingConstant
Themes Analyze

9.306. No String With Append

PHP 7 doesn’t allow the usage of [] with strings. [] is an array-only operator.

<?php

$string = 'abc';

// Not possible in PHP 7
$string[] = 'd';

?>

This was possible in PHP 5, but is now forbidden in PHP 7.

Short name Php/NoStringWithAppend
Themes CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56

9.307. No Substr Minus One

Negative index were introduced in PHP 7.1. This syntax is not compatible with PHP 7.0 and older.

<?php
$string = 'abc';

echo $string[-1]; // c

echo $string[1]; // a

?>

Seel also Generalize support of negative string offsets.

Short name Php/NoSubstrMinusOne
Themes CompatibilityPHP53, CompatibilityPHP70, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56

9.308. No Substr() One

Use array notation $string[$position] to reach a single byte in a string.

There are two ways to access a byte in a string : substr() and $v[$pos];

The second style is more readable. It may be up to four times faster, though it is a micro-optimization. It is recommended to use it.

PHP 7.1 also introduces the support of negative offsets as string index : negative offset are also reported.

<?php

$string = ab人cde;

echo substr($string, $pos, 1);
echo $string[$pos];
echo mb_substr($string, $pos, 1);

// $pos = 1
// bbb
// $pos = 2
// ??人

?>

Beware that substr() and $v[$pos] are similar, while ‘mb_substr() is not. The first function works on bytes, while the latter works on characters.

Short name Structures/NoSubstrOne
Themes Analyze, Performances, CompatibilityPHP71, Suggestions

9.309. No array_merge() In Loops

‘array_merge() is memory intensive : every call will duplicate the arguments in memory, before merging them.

To handle arrays that may be quite big, it is recommended to avoid using ‘array_merge() in a loop. Instead, one should use ‘array_merge() with as many arguments as possible, making the merge a on time call.

<?php

// A large multidimensional array
$source = ['a' => ['a', 'b', /*...*/],
           'b' => ['b', 'c', 'd', /*...*/],
           /*...*/
           ];

// Faster way
$b = array();
foreach($source as $key => $values) {
    //Collect in an array
    $b[] = $values;
}

// One call to array_merge
$b = call_user_func_array('array_merge', $b);
// or with variadic
$b = call_user_func('array_merge', ..$b);

// Fastest way (with above example, without checking nor data pulling)
$b = call_user_func_array('array_merge', array_values($source))
// or
$b = call_user_func('array_merge', ...array_values($source))

// Slow way to merge it all
$b = array();
foreach($source as $key => $values) {
    $b = array_merge($b, $values);
}

?>

Note that ‘array_merge_recursive() and ‘file_put_contents() are affected and reported the same way.

Short name Performances/ArrayMergeInLoops
Themes Analyze, Performances
ClearPHP no-array_merge-in-loop
Examples Tine20

9.310. No get_class() With Null

It is not possible to pass explicitly null to get_class() to get the current’s class name. Since PHP 7.2, one must call get_class() without arguments to achieve that result.

<?php

class A {
  public function f() {
    // Gets the classname
    $classname = get_class();

    // Gets the classname and a warning
    $classname = get_class(null);
  }
}

$a = new A();
$a->f('get_class');

?>
Short name Structures/NoGetClassNull
Themes Analyze, CompatibilityPHP53, CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP72

9.311. Non Ascii Variables

PHP supports variables with certain characters. The variable name must only include letters, figures, underscores and ASCII characters from 128 to 255.

In practice, letters outside the scope of a-zA-Z0-9 are rare, and require more care when editing the code or passing it from OS to OS.

<?php

class  {
    // An actual working class in PHP.
    public function '__construct() {
        echo '__CLASS__;
    }
}

$people = new ();

?>

See also Variables.

Short name Variables/VariableNonascii
Themes Analyze

9.312. Non Static Methods Called In A Static

Static methods have to be declared as such (using the static keyword). Then, one may call them without instantiating the object.

PHP 7.0, and more recent versions, yield a deprecated error : ‘Non-static method A::B() should not be called statically’ .

PHP 5 and older doesn’t check that a method is static or not : at any point, you may call one method statically :

<?php
    class x {
        static public function sm( ) { echo '__METHOD__.\n; }
        public public sm( ) { echo '__METHOD__.\n; }
    }

    x::sm( ); // echo x::sm
?>

It is a bad idea to call non-static method statically. Such method may make use of special variable $this, which will be undefined. PHP will not check those calls at compile time, nor at running time.

It is recommended to update this situation : make the method actually static, or use it only in object context.

Note that this analysis reports all static method call made on a non-static method, even within the same class or class hierarchy. PHP silently accepts static call to any in-family method.

<?php
    class x {
        public function foo( ) { self::bar() }
        public function bar( ) { echo '__METHOD__.\n; }
    }
?>

See also static keyword.

Short name Classes/NonStaticMethodsCalledStatic
Themes Analyze, CompatibilityPHP56, CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55

9.313. Non-constant Index In Array

Undefined constants revert as strings in Arrays. They are also called barewords.

In ‘$array[index]’, PHP cannot find index as a constant, but, as a default behavior, turns it into the string ‘index’.

This default behavior raise concerns when a corresponding constant is defined, either using ‘define() or the const keyword (outside a class). The definition of the index constant will modify the behavior of the index, as it will now use the constant definition, and not the ‘index’ string.

<?php

// assign 1 to the element index in $array
// index will fallback to string
$array[index] = 1;
//PHP Notice:  Use of undefined constant index - assumed 'index'

echo $array[index];      // display 1 and the above error
echo $array[index];    // display 1
echo $array[index];  // Syntax error


define('index', 2);

 // now 1 to the element 2 in $array
 $array[index] = 1;

?>

It is recommended to make index a real string (with ‘ or “), or to define the corresponding constant to avoid any future surprise.

Note that PHP 7.2 removes the support for this feature : PHP RFC: Deprecate and Remove Bareword (Unquoted) Strings.

Short name Arrays/NonConstantArray
Themes Analyze

9.314. Non-lowercase Keywords

Usual convention is to write PHP keywords (like as, foreach, switch, case, ‘break, etc.) all in lowercase.

<?php

// usual PHP convention
foreach($array as $element) {
    echo $element;
}

// unusual PHP conventions
Foreach($array AS $element) {
    eCHo $element;
}

?>

PHP do understand them in lowercase, UPPERCASE or WilDCase, so there is nothing compulsory here. Although, it will look strange to many.

Short name Php/UpperCaseKeyword
Themes Coding Conventions

9.315. Nonce Creation

Mark the creation of nonce by Wordpress. Nonce may be created with the Wordpress functions wp_nonce_field(), wp_nonce_url() and wp_nonce_create().

<?php

// Create an nonce for a link.
$nonce = wp_create_nonce( 'my-nonce' );

echo '<a href="myplugin.php?do_something=some_action&_wpnonce='.$nonce.'">Do some action</a>';

?>

See also Wordpress Nonce.

Short name Wordpress/NonceCreation
Themes Wordpress

9.316. Not A Scalar Type

int is the actual PHP scalar type, not integer.

PHP 7 introduced several scalar types, in particular int, bool and float. Those three types are easily mistaken with integer, boolean, real and double.

Unless you have created those classes, you may get some strange error messages.

<?php

// This expects a scalar of type 'integer'
function foo(int $i) {}

// This expects a object of class 'integer'
function abr(integer $i) {}

?>

Thanks to Benoit Viguier for the original idea for this analysis.

See also Type declarations.

Short name Php/NotScalarType
Themes Analyze

9.317. Not Not

Double not makes a boolean, not a true.

This is a wrongly done casting to boolean. PHP supports (boolean) to do the same, faster and cleaner.

<?php
    // Wrong type casting
    $b = !!$x;

    // Explicit code
    $b = (boolean) $x;
?>
Short name Structures/NotNot
Themes Analyze
ClearPHP no-implied-cast

9.318. Null On New

Until PHP 7, some classes instantiation could yield null, instead of throwing an exception.

After issuing a ‘new’ with those classes, it was important to check if the returned object were null or not. No exception were thrown.

<?php

// Example extracted from the wiki below
$mf = new MessageFormatter('en_US', '{this was made intentionally incorrect}');
if ($mf === null) {
    echo 'Surprise!';
}

?>

This inconsistency has been cleaned in PHP 7 : see See Internal Constructor Behavior

See also PHP RFC: Constructor behaviour of internal classes.

Short name Classes/NullOnNew
Themes CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56

9.319. Objects Don’t Need References

There is no need to create references for objects, as those are always passed by reference when used as arguments.

<?php

    $object = new stdClass();
    $object->name = 'a';

    foo($object);
    print $object->name; // Name is 'b'

    // No need to make $o a reference
    function foo(&$o) {
        $o->name = 'b';
    }

    $array = array($object);
    foreach($array as &$o) { // No need to make this a reference
        $o->name = 'c';
    }

?>

See also Passing by reference.

Short name Structures/ObjectReferences
Themes Analyze
ClearPHP no-references-on-objects

9.320. Old Style Constructor

PHP classes used to have the method bearing the same name as the class acts as the constructor. That was PHP 4, and early PHP 5.

The manual issues a warning about this syntax : ‘Old style constructors are DEPRECATED in PHP 7.0, and will be removed in a future version. You should always use ‘__construct() in new code.’

<?php

namespace {
    // Global namespace is important
    class foo {
        function foo() {
            // This acts as the old-style constructor, and is reported by PHP
        }
    }

    class bar {
        function '__construct() { }
        function bar() {
            // This doesn't act as constructor, as bar has a '__construct() method
        }
    }
}

namespace Foo\Bar{
    class foo {
        function foo() {
            // This doesn't act as constructor, as bar is not in the global namespace
        }
    }
}

?>

This is no more the case in PHP 5, which relies on ‘__construct() to do so. Having this old style constructor may bring in confusion, unless you are also supporting old time PHP 4.

Note that classes with methods bearing the class name, but inside a namespace are not following this convention, as this is not breaking backward compatibility. Those are excluded from the analyze.

See also Constructors and Destructors ¶.

Short name Classes/OldStyleConstructor
Themes Analyze
ClearPHP no-php4-class-syntax

9.321. Old Style __autoload()

Avoid __autoload(), only use spl_register_autoload().

__autoload() will be deprecated in PHP 7.2 and possibly removed in later version.

__autoload() may only be declared once, and cannot be modified later. This creates potential conflicts between libraries that try to set up their own autoloading schema.

On the other hand, spl_register_autoload() allows registering and de-registering multiple autoloading functions or methods.

<?php

// Modern autoloading.
function myAutoload($class){}
spl_register_autoload('myAutoload');

// Old style autoloading.
function __autoload($class){}

?>

Do not use the old __autoload() function, but rather the new spl_register_autoload() function.

See also Autoloading Classe.

Short name Php/oldAutoloadUsage
Themes Analyze
ClearPHP use-smart-autoload

9.322. One If Is Sufficient

Switch the if then structures to reduce the amount of conditions to read.

<?php

// Less conditions are written here.
     if($b == 2) {
        if($a == 1) {
             ++$c;
     }
        else {
             ++$d;
     }
    }

// ($b == 2) is double here
    if($a == 1) {
     if($b == 2) {
             ++$c;
     }
    }
    else {
     if($b == 2) {
             ++$d;
     }
    }
?>
Short name Structures/OneIfIsSufficient
Themes Suggestions

9.323. One Letter Functions

One letter functions seems to be really short for a meaningful name. This may happens for very high usage functions, so as to keep code short, but such functions should be rare.

<?php

// Always use a meaningful name
function addition($a, $b) {
    return $a + $b;
}

// One letter functions are rarely meaningful
function f($a, $b) {
    return $a + $b;
}

?>
Short name Functions/OneLetterFunctions
Themes Analyze

9.324. One Variable String

These strings only contains one variable or property or array.

<?php

$a = 0;
$b = $a; // This is a one-variable string

// Better way to write the above
$b = (string) $a;

// Alternatives :
$b2 = $a[1]; // This is a one-variable string
$b3 = $a->b; // This is a one-variable string
$c = d;
$d = D;
$b4 = "{$$c}";
$b5 = "{$a->foo()}";

?>

If the goal is to convert it to a string, use the type casting (string) operator : it is then clearer to understand the conversion. It is also marginally faster, though very little.

Short name Type/OneVariableStrings
Themes Analyze

9.325. Only Variable Passed By Reference

When an argument is expected by reference, it is compulsory to provide a container. A container may be a variable, an array, a property or a static property.

This may be linted by PHP, when the function definition is in the same file as the function usage. This is silently linted if definition and usage are separated, if the call is dynamical or made as a method.

<?php

function foo(&$bar) { /'**/ }

function &bar() { /'**/ }

// This is not possible : 'strtolower() returns a value
foo(strtolower($string));

// This is valid : bar() returns a reference
foo(bar($string));

?>

This analysis currently covers functioncalls and static methodcalls, but omits methodcalls.

Short name Functions/OnlyVariablePassedByReference
Themes Analyze
Examples Dolphin, PhpIPAM

9.326. Only Variable Returned By Reference

Function can’t return literals by reference.

When a function returns a reference, it is only possible to return variables, properties or static properties.

Anything else, like literals or static expressions, yield a warning at execution time.

<?php

// Can't return a literal number
function &foo() {
    return 3 + 'rand();
}

// bar must return values that are stored in a
function &bar() {
    $a = 3 + 'rand();
    return $a;
}

?>
Short name Structures/OnlyVariableReturnedByReference
Themes Analyze

9.327. Or Die

Classic old style failed error management.

<?php

// In case the connexion fails, this kills the current script
mysql_connect('localhost', $user, $pass) or 'die();

?>

Interrupting a script will leave the application with a blank page, will make your life miserable for testing. Just don’t do that.

Short name Structures/OrDie
Themes Analyze
ClearPHP no-implied-if

9.328. Order Of Declaration

The order used to declare members and methods has a great impact on readability and maintenance. However, practices varies greatly. As usual, being consistent is the most important and useful.

The suggested order is the following : traits, constants, properties, methods. Optional characteristics, like final, static… are not specified. Special methods names are not specified.

<?php

class x {
    use traits;

    const CONSTANTS = 1;
    const CONSTANTS2 = 1;
    const CONSTANTS3 = 1;

    private $property = 2;
    private $property2 = 2;
    private $property3 = 2;

    public function foo() {}
    public function foo2() {}
    public function foo3() {}
    public function foo4() {}
}

?>
Short name Classes/OrderOfDeclaration
Themes Coding Conventions

9.329. Overwriting Variable

Replacing the content of a variable by something different is prone to errors. For example, it is not obvious if the $text variable is plain text or HTML text.

<?php

// Confusing
$text = htmlentities($text);

// Better
$textHTML = htmlentities($text);

?>

Besides, it is possible that the source is needed later, for extra processing.

Note that accumulators, like += .= or [] etc., that are meant to collect lots of values with consistent type are OK.

Short name Variables/Overwriting
Themes Analyze

9.330. Overwritten Exceptions

In catch blocks, it is good practice not to overwrite the incoming exception, as information about the exception will be lost.

<?php

try {
    doSomething();
} catch (SomeException $e) {
    // $e is overwritten
    $e = new anotherException($e->getMessage());
    throw $e;
} catch (SomeOtherException $e) {
    // $e is chained with the next exception
    $e = new Exception($e->getMessage(), 0, $e);
    throw $e;
}

?>
Short name Exceptions/OverwriteException
Themes Analyze, Suggestions

9.331. Overwritten Literals

The same variable is assigned a literal twice. It is possible that one of the assignation is too much.

This analysis doesn’t take into account the distance between two assignations : it may report false positives when the variable is actually used for several purposes, and, as such, assigned twice with different values.

<?php

function foo() {
    // Two assignations in a short sequence : one is too many.
    $a = 1;
    $a = 2;

    for($i = 0; $i < 10; $i++) {
        $a += $i;
    }
    $b = $a;

    // New assignation. $a is now used as an array.
    $a = array(0);
}

?>
Short name Variables/OverwrittenLiterals
Themes Analyze

9.332. PHP 7.0 New Classes

Those classes are now declared natively in PHP 7.0 and should not be declared in custom code.

There are 8 new classes : Error, ‘ParseError, TypeError, ArithmeticError, DivisionByZeroError, ClosedGeneratorException, ReflectionGenerator, ReflectionType, AssertionError.

<?php

namespace {
    // Global namespace
    class Error {
        // Move to a namespace
        // or, remove this class
    }
}

namespace B {
    class Error {
        // This is OK : in a namespace
    }
}

?>
Short name Php/Php70NewClasses
Themes CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56

9.333. PHP 7.0 New Interfaces

The following interfaces are introduced in PHP 7.0. They shouldn’t be defined in custom code.

Short name Php/Php70NewInterfaces
Themes CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56

9.334. PHP 7.0 Removed Directives

List of directives that are removed in PHP 7.0.

Short name Php/Php70RemovedDirective
Themes CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP73

9.335. PHP 7.1 Microseconds

PHP supports microseconds in DateTime class and date_create() function. This was introduced in PHP 7.1.

In previous PHP versions, those dates only used seconds, leading to lazy comparisons :

<?php

$now = date_create();
usleep(10);              // wait for 0.001 ms
var_dump($now == date_create());

?>

This code displays true in PHP 7.0 and older, (unless the code was run too close from the next second). In PHP 7.1, this is always false.

This is also true with Datetime :

<?php

$now = new DateTime();
usleep(10);              // wait for 0.001 ms
var_dump((new DateTime())->format('u') == $now->format('u'));

?>

This evolution impacts mostly exact comparisons (== and ===). Non-equality (!= and !==) will probably be always true, and should be reviewed.

See also Backward incompatible changes.

Short name Php/Php71microseconds
Themes CompatibilityPHP71

9.336. PHP 7.1 Removed Directives

List of directives that are removed in PHP 7.1.

Short name Php/Php71RemovedDirective
Themes CompatibilityPHP71

9.337. PHP 7.2 Deprecations

Several functions are deprecated in PHP 7.2.

Deprecated functions and extensions are reported in a separate analysis.

Short name Php/Php72Deprecation
Themes CompatibilityPHP72

9.338. PHP 7.2 Object Keyword

‘object’ is a PHP keyword. It can’t be used for class, interface or trait name.

This is the case since PHP 7.2.

<?php

// Valid until PHP 7.2
class object {}

// Altough it is really weird anyway...

?>

See also List of Keywords.

Short name Php/Php72ObjectKeyword
Themes CompatibilityPHP72

9.339. PHP 7.2 Removed Functions

The following PHP native functions were removed in PHP 7.2.

  • png2wbmp
  • jpeg2wbmp
Short name Php/Php72RemovedFunctions
Themes CompatibilityPHP72

9.340. PHP 7.3 Last Empty Argument

PHP allows the last element of any functioncall to be empty. The argument is then not send.

This was introduced in PHP 7.3, and is not backward compatible.

The last empty line is easier on the VCS, allowing clearer text diffs.

<?php

function foo($a, $b) {
    print_r('func_get_args());
}


foo(1,
    2,
    );

foo(1);


?>

See also Allow a trailing comma in function calls.

Short name Php/PHP73LastEmptyArgument
Themes CompatibilityPHP73

9.341. PHP 70 Removed Functions

The following PHP native functions were removed in PHP 7.0.

  • ereg
  • ereg_replace
  • eregi
  • eregi_replace
  • split
  • spliti
  • sql_regcase
  • magic_quotes_runtime
  • set_magic_quotes_runtime
  • call_user_method
  • call_user_method_array
  • set_socket_blocking
  • mcrypt_ecb
  • mcrypt_cbc
  • mcrypt_cfb
  • mcrypt_ofb
  • datefmt_set_timezone_id
  • imagepsbbox
  • imagepsencodefont
  • imagepsextendfont
  • imagepsfreefont
  • imagepsloadfont
  • imagepsslantfont
  • imagepstext
Short name Php/Php70RemovedFunctions
Themes CompatibilityPHP70, CompatibilityPHP71

9.342. PHP 72 Removed Interfaces

The following PHP native interfaces were removed in PHP 7.2.

  • SessionHandlerInterface
  • SessionIdInterface
  • SessionUpdateTimestampHandlerInterface
Short name Php/Php72RemovedInterfaces
Themes CompatibilityPHP53, CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56

9.343. PHP Keywords As Names

PHP has a set of reserved keywords. It is recommended not to use those keywords for names structures.

PHP does check that a number of structures, such as classes, methods, interfaces… can’t be named or called using one of the keywords. However, in a few other situations, no check are enforced. Using keywords in such situation is confusing.

<?php

// This keyword is reserved since PHP 7.2
class object {
    // _POST is used by PHP for the $_POST variable
    // This methods name is probably confusing,
    // and may attract more than its share of attention
    function _POST() {

    }

}

?>
Short name Php/ReservedNames
Themes Analyze

9.344. PHP5 Indirect Variable Expression

Indirect variable expressions changes between PHP 5 an 7.

The following structures are evaluated differently in PHP 5 and 7. It is recommended to review them or switch to a less ambiguous syntax.

<?php

// PHP 7
$foo = 'bar';
$bar['bar']['baz'] = 'foobarbarbaz';
echo $$foo['bar']['baz'];
echo ($$foo)['bar']['baz'];

// PHP 5
$foo['bar']['baz'] = 'bar';
$bar = 'foobarbazbar';
echo $$foo['bar']['baz'];
echo ${$foo['bar']['baz']};

?>

See Backward incompatible changes PHP 7.0

Expression PHP 5 interpretation PHP 7 interpretation
$$foo[‘bar’][‘baz’] $foo->$bar[‘baz’] $foo->$bar[‘baz’]() Foo::$bar[‘baz’]() ${$foo[‘bar’][‘baz’]} $foo->{$bar[‘baz’]} $foo->{$bar[‘baz’]}() Foo::{$bar[‘baz’]}() ($$foo)[‘bar’][‘baz’] ($foo->$bar)[‘baz’] ($foo->$bar)[‘baz’]() (Foo::$bar)[‘baz’]()
Short name Variables/Php5IndirectExpression
Themes CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56

9.345. PHP7 Dirname

With PHP 7, dirname has a second argument that represents the number of parent folder to follow. This prevent us from using nested ‘dirname() calls to reach an grand-parent direct.

<?php
$path = '/a/b/c/d/e/f';

// PHP 7 syntax
$threeFoldersUp = dirname($path, 3);

// PHP 5 syntax
$threeFoldersUp = dirname(dirname(dirname($path)));

?>
Short name Structures/PHP7Dirname
Themes CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, Suggestions

9.346. Parent First

When calling parent constructor, always put it first in the ‘__construct method. It ensures the parent is correctly build before the child start using values.

<?php

class father {
    protected $name = null;

    function '__construct() {
        $this->name = init();
    }
}

class goodSon {
    function '__construct() {
        // parent is build immediately,
        parent::'__construct();
        echo my name is.$this->name;
    }
}

class badSon {
    function '__construct() {
        // This will fail.
        echo my name is.$this->name;

        // parent is build later,
        parent::'__construct();
    }
}

?>

This analysis cannot be applied to Exceptions.

Short name Classes/ParentFirst
Themes Analyze, Suggestions

9.347. Parent, Static Or Self Outside Class

Parent, static and self keywords must be used within a class or a trait. They make no sens outside a class or trait scope, as self and static refers to the current class and parent refers to one of parent above.

PHP 7.0 and later detect their usage at compile time, and emits a fatal error.

<?php

class x {
    const Y = 1;

    function foo() {
        // self is \x
        echo self::Y;
    }
}

const Z = 1;
// This doesn't compile anymore
echo self::Z;

?>

Static may be used in a function or a closure, but not globally.

Short name Classes/PssWithoutClass
Themes Analyze

9.348. Parenthesis As Parameter

Using parenthesis around parameters used to silent some internal check. This is not the case anymore in PHP 7, and should be fixed by removing the parenthesis and making the value a real reference.

<?php

// PHP 7 sees through parenthesis
$d = foo(1, 2, $c);

// Avoid parenthesis in arguments
$d = foo(1, 2, ($c));

?>
Short name Php/ParenthesisAsParameter
Themes CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP72, CompatibilityPHP73

9.349. Pathinfo() Returns May Vary

‘pathinfo() function returns an array whose content may vary. It is recommended to collect the values after check, rather than directly.

<?php

$file = '/a/b/.c';
//$extension may be missing, leading to empty $filename and filename in $extension
list( $dirname, $basename, $extension, $filename ) = array_values( pathinfo($file) );

//Use PHP 7.1 list() syntax to assign correctly the values, and skip 'array_values()
//This emits a warning in case of missing index
['dirname'   => $dirname,
 'basename'  => $basename,
 'extension' => $extension,
 'filename'  => $filename ] = pathinfo($file);

//This works without warning
$details = pathinfo($file);
$dirname   = $details['dirname'] ?? getpwd();
$basename  = $details['basename'] ?? '';
$extension = $details['extension'] ?? '';
$filename  = $details['filename'] ?? '';

?>

The same applies to ‘parse_url(), which returns an array with various index.

Short name Php/PathinfoReturns
Themes Analyze

9.350. Php 7 Indirect Expression

Those are variable indirect expressions that are interpreted differently in PHP 5 and PHP 7.

You should check them so they don’t behave strangely.

<?php

// Ambiguous expression :
$b = $$foo['bar']['baz'];
echo $b;

$foo = array('bar' => array('baz' => 'bat'));
$bat = 'PHP 5.6';

// In PHP 5, the expression above means :
$b = $\{$foo['bar']['baz']};
$b = 'PHP 5.6';

$foo = 'a';
$a = array('bar' => array('baz' => 'bat'));

// In PHP 7, the expression above means :
$b = ($$foo)['bar']['baz'];
$b = 'bat';

?>

See also Changes to variable handling.

Short name Variables/Php7IndirectExpression
Themes CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP70

9.351. Php 7.1 New Class

New classes, introduced in PHP 7.1. If classes where created with the same name, in current code, they have to be moved in a namespace, or removed from code to migrate safely to PHP 7.1.

The new class is : ReflectionClassConstant. The other class is ‘Void’ : this is forbidden as a classname, as Void is used for return type hint.

<?php

class ReflectionClassConstant {
    // Move to a namespace, do not leave in global
    // or, remove this class
}

?>
Short name Php/Php71NewClasses
Themes CompatibilityPHP53, CompatibilityPHP70, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56

9.352. Php 7.2 New Class

New classes, introduced in PHP 7.2. If classes where created with the same name, in current code, they have to be moved in a namespace, or removed from code to migrate safely to PHP 7.2.

The new class is : HashContext.

<?php

namespace {
    // Global namespace
    class HashContext {
        // Move to a namespace
        // or, remove this class
    }
}

namespace B {
    class HashContext {
        // This is OK : in a namespace
    }
}

?>
Short name Php/Php72NewClasses
Themes CompatibilityPHP53, CompatibilityPHP70, CompatibilityPHP71, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56, CompatibilityPHP72

9.353. Php/NoReferenceForTernary

The ternary operator and the null coalescing operator are both expressions that only return values, and not a variable.

This means that any provided reference will be turned into its value. While this is usually invisible, it will raise a warning when a reference is expected. This is the case with methods returning a reference.

This applies to methods, functions and closures.

<?php

// This works
function &foo($a, $b) {
    if ($a === 1) {
        return $b;
    } else {
        return $a;
    }
}

// This raises a warning, as the operator returns a value
function &foo($a, $b) { return $a === 1 ? $b : $a; }

?>
See also Null Coalescing Operator,
Ternary Operator.
Short name Php/NoReferenceForTernary
Themes Analyze

9.354. Php7 Relaxed Keyword

Most of the traditionnal PHP keywords may be used inside classes, trait or interfaces.

<?php

// Compatible with PHP 7.0 +
class foo {
    // as is a PHP 5 keyword
    public function as() {

    }
}

?>

This was not the case in PHP 5, and will yield parse errors.

Short name Php/Php7RelaxedKeyword
Themes CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56

9.355. Phpinfo

‘phpinfo() is a great function to learn about the current configuration of the server.

<?php

if (DEBUG) {
    'phpinfo();
}

?>

If left in the production code, it may lead to a critical leak, as any attacker gaining access to this data will know a lot about the server configuration. It is advised to never leave that kind of instruction in a production code.

Short name Structures/PhpinfoUsage
Themes Analyze, Security

9.356. Possible Increment

This expression looks like a typo : a missing + would change the behavior.

The same pattern is not reported with -, as it is legit expression. + sign is usually understated, rather than explicit.

<?php

// could it be a ++$b ?
$a = +$b;

?>
See also Incrementing/Decrementing Operators and
Arithmetic Operators.
Short name Structures/PossibleIncrement
Themes Suggestions

9.357. Possible Infinite Loop

Loops on files that can’t be open results in infinite loop.

‘fgets(), and functions like fgetss, fgetcsv, ‘fread(), return false when they finish reading, or can’t access the file.

In case the file is not accessible, comparing the result of the reading to something that is falsy, leads to a permanent valid condition. The will only finish when the max_execution_time is reached.

<?php

$file = fopen('/path/to/file.txt', 'r');
// when 'fopen() fails, the next loops is infinite
// 'fgets() will always return false, and while will always be true.
while($line = fgets($file) != 'a') {
    doSomething();
}

?>

It is recommended to check the file resources when they are opened, and always use === or !== to compare readings. ‘feof() is also a reliable function here.

Short name Structures/PossibleInfiniteLoop
Themes Analyze

9.358. Pre-increment

When possible, use the pre-increment operator (++$i or –$i) instead of the post-increment operator ($i++ or $i–).

The latter needs an extra memory allocation that costs about 10% of performances.

<?php

// ++$i should be preferred over $i++, as current value is not important
for($i = 0; $i <10; ++$i) {
    // do Something
}

// ++$b and $b++ have different impact here, since $a will collect $b + 1 or $b, respectively.
$a = $b++;

?>

This is a micro-optimisation. However, its usage is so widespread, including within loops, that it may eventually be visible. As such, it is recommended to adopt this rule, and only consider changing legacy code as they are refactored for other reasons.

Short name Performances/PrePostIncrement
Themes Analyze, Performances

9.359. Prepare Placeholder

$wpdb->prepare() only allows %d, %s and %F as placeholder. All others are not available. They are even enforced since Wordpress 4.8.3.

In particular, absolute references are not allowed anymore, due to an injection vulnerability.

<?php

// valid place holders
  $query = $wpdb->prepare('SELECT * FROM table WHERE col = %s and col2 = %1$s and col3 = %F', 'string', 1, 1.2);

// valid place holders : invalid Wordpress placeholder
// This may be a valid vsprintf placeholder.
  $query = $wpdb->prepare('SELECT * FROM table WHERE col = %b', $integerDisplayedAsBinary);

// valid place holders : absolute reference. $var is used twice
  $query = $wpdb->prepare('SELECT * FROM table WHERE col = %s and %1$s', $var);

?>

See also ‘vprintf() and Disclosure: WordPress WPDB SQL Injection - Technical.

Short name Wordpress/PreparePlaceholder
Themes Wordpress

9.360. Preprocess Arrays

Using long list of assignations for initializing arrays is significantly slower than the declaring them as an array.

<?php

// Slow way
$a = []; // also with $a = array();
$a[1] = 2;
$a[2] = 3;
$a[3] = 5;
$a[4] = 7;
$a[5] = 11;

// Faster way
$a = [1 => 2,
      2 => 3,
      3 => 5,
      4 => 7,
      5 => 11];

// Even faster way if indexing is implicit
$a = [2, 3, 5, 7, 11];

?>

If the array has to be completed rather than created, it is also faster to use += when there are more than ten elements to add.

<?php

// Slow way
$a = []; // also with $a = array();
$a[1] = 2;
$a[2] = 3;
$a[3] = 5;
// some expressions to get $seven and $eleven
$a[4] = $seven;
$a[5] = $eleven;

// Faster way
$a = [1 => 2,
      2 => 3,
      3 => 5];
// some expressions to get $seven and $eleven
$a += [4 => $seven,
       5 => $eleven];

// Even faster way if indexing is implicit
$a = [2, 3, 5];
// some expressions to get $seven and $eleven
$a += [$seven, $eleven];

?>
Short name Arrays/ShouldPreprocess
Themes Analyze, Suggestions, Suggestions

9.361. Preprocessable

The following expression are made of literals or already known values : they may be fully calculated before running PHP.

<?php

// Building an array from a string
$name = 'PHP'.' '.'7.2';

// Building an array from a string
$list = explode(',', 'a,b,c,d,e,f');

// Calculating a power
$kbytes = $bytes / pow(2, 10);

// This will never change
$name = ucfirst(strtolower('PARIS'));

?>

By doing so, this will reduce the amount of work of PHP.

Short name Structures/ShouldPreprocess
Themes none

9.363. Printf Number Of Arguments

The number of arguments provided to ‘printf() or ‘vprintf() doesn’t match the format string.

Extra arguments are ignored, and are dead code as such. Missing arguments are reported with a warning, and nothing is displayed.

<?php

// not enough
printf(' a %s ', $a1);
// OK
printf(' a %s ', $a1, $a2);
// too many
printf(' a %s ', $a1, $a2, $a3);

// not enough
sprintf(' a %s ', $a1);
// OK
\sprintf(' a %s ', $a1, $a2);
// too many
sprintf(' a %s ', $a1, $a2, $a3);

?>

See also printf and sprintf.

Short name Structures/PrintfArguments
Themes Analyze

9.364. Private Function Usage

Wordpress has a list of ‘private’ function, that is reserves for itself. It is forbidden to use them.

<?php

///wp-includes/class-wp-theme.php, line 1139
$types = explode( ',', _cleanup_header_comment( $type[1] ) );

?>

See also Category:Private Functions.

Short name Wordpress/PrivateFunctionUsage
Themes Wordpress

9.365. Processing Collector

When accumulating data in a variable, within a loop, it is slow to apply repeatedly a function to the variable.

The example below illustrate the problem : $collector is build with element from $array. $collector actually gets larger and larger, slowing the ‘in_array() call each time.

It is better to apply the ‘preg_replace() to $a, a short variable, and then, add $a to the collector.

<?php

// Fast way
$collector = '';
foreach($array as $a){
    $a = preg_replace('/__(.*?)__/', '<b>$1</b>', $a);
    $collector .= $a;
}

// Slow way
$collector = '';
foreach($array as $a){
    $collector .= $a;
    $collector = preg_replace('/__(.*?)__/', '<b>$1</b>', $collector);
}

?>
Short name Performances/RegexOnCollector
Themes Performances

9.366. Property Could Be Local

A property only used in one method may be turned into a local variable.

Public properties are omitted here : they may be modified anywhere in the code.

<?php

class x {
    private $foo = 1;

    function bar() {
        $this->foo++;

        return $this->foo;
    }
}

?>
Short name Classes/PropertyCouldBeLocal
Themes Analyze

9.367. Property Could Be Private Property

The following properties are never used outside their class of definition Given the analyzed code, they could be set as private.

<?php

class foo {
    public $couldBePrivate = 1;
    public $cantdBePrivate = 1;

    function bar() {
        // couldBePrivate is used internally.
        $this->couldBePrivate = 3;
    }
}

class foo2 extends foo {
    function bar2() {
        // cantdBePrivate is used in a child class.
        $this->cantdBePrivate = 3;
    }
}

//$couldBePrivate is not used outside
$foo = new foo();

//$cantdBePrivate is used outside the class
$foo->cantdBePrivate = 2;

?>

Note that dynamic properties (such as $x->$y) are not taken into account.

Short name Classes/CouldBePrivate
Themes Analyze

9.368. Property Used In One Method Only

Properties should be used in several methods. When a property is used in only one method, this should have be of another shape.

Properties used in one method only may be used several times, and read only. This may be a class constant. Such properties are meant to be overwritten by an extending class, and that’s possible with class constants.

Properties that read and written may be converted into a variable, static to the method. This way, they are kept close to the method, and do not pollute the object’s properties.

<?php

class foo {
    private $once = 1;
    const ONCE = 1;
    private $counter = 0;

    function bar() {
        // $this->once is never used anywhere else.
        someFunction($this->once);
        someFunction(self::ONCE);   // Make clear that it is a
    }

    function bar2() {
        static $localCounter = 0;
        $this->counter++;

        // $this->once is only used here, for distinguising calls to someFunction2
        if ($this->counter > 10) { // $this->counter is used only in bar2, but it may be used several times
            return false;
        }
        someFunction2($this->counter);

        // $localCounter keeps track for all the calls
        if ($localCounter > 10) {
            return false;
        }
        someFunction2($localCounter);
    }
}

?>

Note : properties used only once are not returned by this analysis. They are omitted, and are available in the analysis Used Once Property.

Short name Classes/PropertyUsedInOneMethodOnly
Themes Analyze

9.369. Property Variable Confusion

Within a class, there is both a property and variables bearing the same name.

<?php
class Object {
    private $x;

    function SetData( ) {
        $this->x = $x + 2;
    }
}
?>

The property and the variable may easily be confused one for another and lead to a bug.

Sometimes, when the property is going to be replaced by the incoming argument, or data based on that argument, this naming schema is made on purpose, indicating that the current argument will eventually end up in the property. When the argument has the same name as the property, no warning is reported.

Short name Structures/PropertyVariableConfusion
Themes Analyze

9.370. Queries In Loops

Avoid querying databases in a loop.

Querying an external database in a loop usually leads to performances problems. This is also called the ‘n + 1 problem’.

This problem applies also to prepared statement : when such statement are called in a loop, they are slower than one-time large queries.

It is recommended to reduce the number of queries by making one query, and dispatching the results afterwards. This is true with SQL databases, graph queries, LDAP queries, etc.

<?php

// Typical N = 1 problem : there will be as many queries as there are elements in $array
$ids = array(1,2,3,5,6,10);

$db = new SQLite3('mysqlitedb.db');

// all the IDS are merged into the query at once
$results = $db->query('SELECT bar FROM foo WHERE id  in ('.implode(',', $id).')');
while ($row = $results->fetchArray()) {
    var_dump($row);
}


// Typical N = 1 problem : there will be as many queries as there are elements in $array
$ids = array(1,2,3,5,6,10);

$db = new SQLite3('mysqlitedb.db');

foreach($ids as $id) {
    $results = $db->query('SELECT bar FROM foo WHERE id = '.$id);
    while ($row = $results->fetchArray()) {
        var_dump($row);
    }
}

?>

This optimisation is not always possible : for example, some SQL queries may not be prepared, like ‘DROP TABLE’, or ‘DESC’. ‘UPDATE’ commands often update one row at a time, and grouping such queries may be counter-productive or unsafe.

Short name Structures/QueriesInLoop
Themes Analyze

9.371. Random Without Try

random_int() and random_bytes() require a try/catch structure around them.

random_int() and random_bytes() emit Exceptions if they meet a problem. This way, failure can’t be mistaken with returning an empty value, which leads to lower security.

<?php

try {
    $salt = random_bytes($length);
} catch (TypeError $e) {
    // Error while reading the provided parameter
} catch (Exception $e) {
    // Insufficient random data generated
} catch (Error $e) {
    // Error with the provided parameter : <= 0
}

?>
Short name Structures/RandomWithoutTry
Themes Security

9.372. Randomly Sorted Arrays

Those literals arrays are written in several places, but in various orders.

This may reduce the reading and proofing of the arrays, and induce confusion.

Unless order is important, it is recommended to always use the same order when defining literal arrays.

<?php

// an array
$set = [1,3,5,9,10];

function foo() {
    // an array, with the same values but different order, in a different context
    $list = [1,3,5,10,9,];
}

// an array, with the same order than the initial one
$inits = [1,3,5,9,10];

?>
Short name Arrays/RandomlySortedLiterals
Themes Analyze, Suggestions

9.373. Redeclared PHP Functions

Function that bear the same name as a PHP function, and that are declared.

This is possible when managing some backward compatibility, like emulating an old function, or preparing for newer PHP version, like emulating new upcoming function.

<?php

if (version_compare(PHP_VERSION, 7.0) > 0) {
    function split($separator, $string) {
        return explode($separator, $string);
    }
}

print_r( split(' ', '2 3'));

?>
Short name Functions/RedeclaredPhpFunction
Themes Analyze

9.374. Redefined Class Constants

Redefined class constants.

Class constants may be redefined, though it is prone to errors when using them, as it is now crucial to use the right class name to access the right value.

<?php

class a {
    const A = 1;
}

class b extends a {
    const A = 2;
}

class c extends c { }

echo a::A, ' ', b::A, ' ', c::A;
// 1 2 2

?>

It is recommended to use distinct names.

Short name Classes/RedefinedConstants
Themes Analyze

9.375. Redefined Default

Classes allows properties to be set with a default value. When those properties get, unconditionally, another value at constructor time, then one of the default value are useless. One of those definition should go : it is better to define properties outside the constructor.

<?php

class foo {
    public $redefined = 1;

    public function '__construct( ) {
        $this->redefined = 2;
    }
}

?>
Short name Classes/RedefinedDefault
Themes Analyze

9.376. Redefined Private Property

Private properties are local to their defined class. PHP doesn’t forbid the re-declaration of a private property in a child class.

However, having two or more properties with the same name, in the class hierarchy tends to be error prone.

<?php

class A {
    private $isReady = true;
}

class B {
    private $isReady = false;
}

?>
Short name Classes/RedefinedPrivateProperty
Themes Analyze
Examples Zurmo

9.377. Register Globals

register_globals was a PHP directive that dumped all incoming variables from GET, POST, COOKIE and FILES as global variables in the called scripts. This lead to security failures, as the variables were often used but not filtered.

Though it is less often found in more recent code, register_globals is sometimes needed in legacy code, that haven’t made the move to eradicate this style of coding. Backward compatible pieces of code that mimic the register_globals features usually create even greater security risks by being run after scripts startup. At that point, some important variables are already set, and may be overwritten by the incoming call, creating confusion in the script.

Mimicking register_globals is achieved with variables variables, ‘extract(), ‘parse_str() and ‘import_request_variables() (Up to PHP 5.4).

<?php

// Security warning ! This overwrites existing variables.
extract($_POST);

// Security warning ! This overwrites existing variables.
foreach($_REQUEST as $var => $value) {
    $$var = $value;
}

?>
Short name Security/RegisterGlobals
Themes Security
Examples TeamPass, XOOPS

9.378. Relay Function

Relay function only hand workload to another one.

Relay functions (or methods) are delegating the actual work to another function or method. They do not have any impact on the results, besides exposing another name for the same feature.

<?php

function myStrtolower($string) {
    return \strtolower($string);
}

?>

Relay functions are typical of transition API, where an old API have to be preserved until it is fully migrated. Then, they may be removed, so as to reduce confusion, and unclutter the API.

Short name Functions/RelayFunction
Themes Analyze

9.379. Repeated Regex

Repeated regex should be centralized.

When a regex is repeatedly used in the code, it is getting harder to update.

<?php

// Regex used several times, at least twice.
preg_match('/^abc_|^square$/i', $_GET['x']);

//.......

preg_match('/^abc_|^square$/i', $row['name']);

// This regex is dynamically built, so it is not reported.
preg_match('/^circle|^'.$x.'$/i', $string);

// This regex is used once, so it is not reported.
preg_match('/^circle|^square$/i', $string);

?>

Regex that are repeated at least once (aka, used twice or more) are reported. Regex that are dynamically build are not reported.

Short name Structures/RepeatedRegex
Themes Analyze

9.380. Repeated print()

Always merge several print or echo in one call.

It is recommended to use echo with multiple arguments, or a concatenation with print, instead of multiple calls to print echo, when outputting several blob of text.

<?php

//Write :
  echo 'a', $b, 'c';
  print 'a' . $b . 'c';

//Don't write :
  print 'a';
  print $b;
  print 'c';
?>
Short name Structures/RepeatedPrint
Themes Analyze, Suggestions
ClearPHP no-repeated-print

9.381. Reserved Keywords In PHP 7

Php reserved names for class/trait/interface. They won’t be available anymore in user space starting with PHP 7.

For example, string, float, false, true, null, resource,… are not acceptable as class name.

<?php

// This doesn't compile in PHP 7.0 and more recent
class null { }

?>

See also List of other reserved words.

Short name Php/ReservedKeywords7
Themes CompatibilityPHP70

9.382. Results May Be Missing

preg_match() may return empty values, if the search fails. It is important to check for the existence of results before assigning them to another variable, or using it.

<?php
    preg_match('/PHP ([0-9\.]+) /', $res, $r);
    $s = $r[1];
    // $s may end up null if preg_match fails.
?>
Short name Structures/ResultMayBeMissing
Themes Analyze

9.383. Rethrown Exceptions

Throwing a caught exception is usually useless and dead code.

When exceptions are caught, they should be processed or transformed, but not rethrown as is.

Those issues often happen when a catch structure was positioned for debug purposes, but lost its usage later.

<?php

try {
    doSomething();
} catch (Exception $e) {
    throw $e;
}

?>
Short name Exceptions/Rethrown
Themes Dead code

9.384. Return True False

These conditional expressions return true/false, depending on the condition. This may be simplified by dropping the control structure altogether.

<?php

if (version_compare($a, $b) >= 0) {
    return true;
} else {
    return false;
}

?>

This may be simplified with :

<?php

return version_compare($a, $b) >= 0;

?>

This may be applied to assignations and ternary operators too.

<?php

if (version_compare($a, $b) >= 0) {
    $a = true;
} else {
    $a = false;
}

$a = version_compare($a, $b) >= 0 ? false : true;

?>
Short name Structures/ReturnTrueFalse
Themes Analyze

9.385. Return With Parenthesis

return statement doesn’t need parenthesis. PHP tolerates them with return statement, but it is recommended not to use them.

<?php

function foo() {
    $a = rand(0, 10);

    // No need for parenthesis
    return $a;

    // Parenthesis are useless here
    return ($a);

    // Parenthesis are useful here: they are needed by the multplication.
    return ($a + 1) * 3;
}

?>
Short name Php/ReturnWithParenthesis
Themes Coding Conventions

9.386. Reuse Variable

A variable is already holding the content that is re-calculated later. Use the cached value.

<?php

function foo($a) {
    $b = strtolower($a);

    // strtolower($a) is already calculated in $b. Just reuse the value.
    if (strtolower($a) === 'c') {
        doSomething();
    }
}

?>
Short name Structures/ReuseVariable
Themes Suggestions

9.387. Safe Curl Options

It is advised to always use CURLOPT_SSL_VERIFYPEER and CURLOPT_SSL_VERIFYHOST when requesting a SSL connexion.

With those tests (by default), the certificate is verified, and if it isn’t valided, the connexion fails : this is a safe behavior.

<?php
$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, https://www.php.net/);

// To be safe, always set this to true
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);

curl_exec($ch);
curl_close($ch);
?>
Short name Security/CurlOptions
Themes Security

9.388. Same Conditions In Condition

At least two consecutive if/then structures use identical conditions. The latter will probably be ignored.

This analysis returns false positive when there are attempt to fix the situation, or to call an alternative solution.

<?php

if ($a == 1) { doSomething(); }
elseif ($b == 1) { doSomething(); }
elseif ($c == 1) { doSomething(); }
elseif ($a == 1) { doSomething(); }
else {}

// Also works on if then else if chains
if ($a == 1) { doSomething(); }
else if ($b == 1) { doSomething(); }
else if ($c == 1) { doSomething(); }
else if ($a == 1) { doSomething(); }
else {}

// This sort of situation generate false postive.
$config = load_config_from_commandline();
if (empty($config)) {
    $config = load_config_from_file();
    if (empty($config)) {
        $config = load_default_config();
    }
}

?>
Short name Structures/SameConditions
Themes Analyze

9.389. Same Variables Foreach

A foreach which uses its own source as a blind variable is actually broken.

Actually, PHP makes a copy of the source before it starts the loop. As such, the same variable may be used for both source and blind value.

Of course, this is very confusing, to see the same variables used in very different ways.

The source will also be destroyed immediately after the blind variable has been turned into a reference.

<?php

$array = range(0, 10);
foreach($array as $array) {
    print $array.PHP_EOL;
}

print_r($array); // display number from 0 to 10.

$array = range(0, 10);
foreach($array as &$array) {
    print $array.PHP_EOL;
}

print_r($array); // display 10

?>
Short name Structures/AutoUnsetForeach
Themes Analyze

9.390. Scalar Or Object Property

Property shouldn’t use both object and scalar syntaxes. When a property may be an object, it is recommended to implement the Null Object pattern : instead of checking if the property is scalar, make it always object.

<?php

class x {
    public $display = 'echo';

    function foo($string) {
        if (is_string($this->display)) {
            echo $this->string;
        } elseif ($this->display 'instanceof myDisplayInterface) {
            $display->display();
        } else {
            print Error when displaying\n;
        }
    }
}

interface myDisplayInterface {
    public function display($string); // does the display in its own way
}

class nullDisplay implements myDisplayInterface {
    // implements myDisplayInterface but does nothing
    public function display($string) {}
}

class x2 {
    public $display = null;

    public function '__construct() {
        $this->display = new nullDisplay();
    }

    function foo($string) {
        // Keep the check, as $display is public, and may get wrong values
        if ($this->display 'instanceof myDisplayInterface) {
            $display->display();
        } else {
            print Error when displaying\n;
        }
    }
}

// Simple class for echo
class echoDisplay implements myDisplayInterface {
    // implements myDisplayInterface but does nothing
    public function display($string) {
        echo $string;
    }
}

?>

See also Null Object Pattern. and The Null Object Pattern.

Short name Classes/ScalarOrObjectProperty
Themes Analyze

9.391. Scalar Typehint Usage

Spot usage of scalar type hint : int, float, boolean and string.

Scalar typehint are PHP 7.0 and more recent. Some, like object, is 7.2.

Scalar typehint were not supported in PHP 5 and older. Then, the typehint is treated as a classname.

<?php

function withScalarTypehint(string $x) {}

function withoutScalarTypehint(someClass $x) {}

?>

See also PHP RFC: Scalar Type Hints and Type declarations.

Short name Php/ScalarTypehintUsage
Themes CompatibilityPHP53, CompatibilityPHP54, CompatibilityPHP55, CompatibilityPHP56

9.392. Sequences In For

For() instructions allows several instructions in each of its parameters. Then, the instruction separator is comma ‘,’, not semi-colon, which is used for separating the 3 arguments.

<?php
   for ($a = 0, $b = 0; $a < 10, $b < 20; $a++, $b += 3) {
    // For loop
   }
?>

This loop will simultaneously increment $a and $b. It will stop only when the last of the central sequence reach a value of false : here, when $b reach 20 and $a will be 6.

This structure is often unknown, and makes the for instruction quite difficult to read. It is also easy to oversee the multiples instructions, and omit one of them. It is recommended not to use it.

Short name Structures/SequenceInFor
Themes Analyze

9.393. Session Lazy Write

Classes that implements SessionHandlerInterface must also implements SessionUpdateTimestampHandlerInterface.

The two extra methods are used to help lazy loading : the first actually checks if a sessionId is available, and the seconds updates the time of last usage of the session data in the session storage.

This was spotted by Nicolas Grekas, and fixed in Symfony [HttpFoundation] Make sessions secure and lazy #24523.

<?php

interface SessionUpdateTimestampHandlerInterface {
    // returns a boolean to indicate that valid data is available for this sessionId, or not.
    function validateId($sessionId);

    //called to change the last time of usage for the session data.
    //It may be a file's touch or full write, or a simple update on the database
    function updateTimestamp($sessionId, $sessionData);
}

?>

See also ` <https://wiki.php.net/rfc/session-read_only-lazy_write>`_ and the Sessions.

Short name Security/SessionLazyWrite
Themes Security

9.395. Setlocale() Uses Constants

setlocal() don’t use strings.

The first argument of ‘setlocale() must be one of the valid constants, LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME, LC_MESSAGES.

<?php

// Use constantes for setlocale first argument
setlocale(LC_ALL, 'nl_NL');
setlocale(\LC_ALL, 'nl_NL');

// Don't use string for setlocale first argument
setlocale('LC_ALL', 'nl_NL');
setlocale('LC_'.'ALL', 'nl_NL');

?>

The PHP 5 usage of strings (same name as above, enclosed in ‘ or “) is not legit anymore in PHP 7 and later.

Short name Structures/SetlocaleNeedsConstants
Themes CompatibilityPHP70

9.396. Several Instructions On The Same Line

Usually, instructions do not share their line : one instruction, one line.

This is good for readability, and help at understanding the code. This is especially important when fast-reading the code to find some special situation, where such double-meaning line way have an impact.

<?php

switch ($x) {
    // Is it a fallthrough or not ?
    case 1:
        doSomething(); 'break;

    // Easily spotted 'break.
    case 1:
        doSomethingElse();
        'break;

    default :
        doDefault();
        'break;
}

?>

See also Object Calisthenics, rule # 5.

Short name Structures/OneLineTwoInstructions
Themes Analyze
Examples Piwigo, Tine20

9.397. Short Open Tags

Usage of short open tags is discouraged. The following files were found to be impacted by the short open tag directive at compilation time. They must be reviewed to ensure no &lt;? tags are found in the code.

Short name Php/ShortOpenTagRequired
Themes Analyze

9.398. Short Syntax For Arrays

Arrays written with the new short syntax.

PHP 5.4 introduced the new short syntax, with square brackets. The previous syntax, based on the array() keyword is still available.

<?php

// All PHP versions array
$a = array(1, 2, 3);

// PHP 5.4+ arrays
$a = [1, 2, 3];

?>

See also Array.

Short name Arrays/ArrayNSUsage
Themes CompatibilityPHP53

9.399. Should Always Prepare

Avoid using variables in string when preparing queries. Always try use the prepare statement by naming variables.

This is particularly sensitive when using where() and having() methods.

Other methods, like limit() or offset() are immune against injections.

<?php
    // OK : all is hardcoded, no chance of injection
    $select->from('foo')->where('x = 5');

    // This is the recommended way to use a variable
    $select->from('foo')->where(['x' => $v]);

    // Concatenation is unsafe
    $select->from('foo')->where('x = '.$v);
    $select->from('foo')->where("x = $v");
?>

This analysis reports a false-postive, even when the included variable is an internal variable : it has been defined in the application, and not acquired from external users. In such case, injection and legit usage of concatenation are undistinguishable.

See also zend-db documentation.

Short name ZendF/Zf3DbAlwaysPrepare
Themes ZendFramework

9.400. Should Be Single Quote

Use single quote for simple strings.

Static content inside a string, that has no single quotes nor escape sequence (such as n or t), should be using single quote delimiter, instead of double quote.

<?php

$a = abc;

// This one is using a special sequence
$b = cde\n;

// This one is using two special sequences
$b = \x03\u{1F418};

?>

If you have too many of them, don’t loose your time switching them all. If you have a few of them, it may be good for consistence.

Short name Type/ShouldBeSingleQuote
Themes Coding Conventions
ClearPHP no-double-quote

9.401. Should Chain Exception

Chain exception to provide more context.

When catching an exception and rethrowing another one, it is recommended to chain the exception : this means providing the original exception, so that the final recipient has a chance to track the origin of the problem. This doesn’t change the thrown message, but provides more information.

Note : Chaining requires PHP > 5.3.0.

<?php
    try {
        throw new Exception('Exception 1', 1);
    } catch (\Exception $e) {
        throw new Exception('Exception 2', 2, $e);
        // Chaining here.

    }
?>

See also Exception::’__construct <http://php.net/manual/en/language.oop5.decon.php>`_ <http://php.net/manual/en/exception.construct.php>`_.

Short name Structures/ShouldChainException
Themes Analyze

9.402. Should Make Alias

Long names should be aliased.

Aliased names are easy to read at the beginning of the script; they may be changed at one point, and update the whole code at the same time. Finally, short names makes the rest of the code readable.

<?php

namespace x\y\z;

use a\b\c\d\e\f\g as Object;

// long name, difficult to read, prone to change.
new a\b\c\d\e\f\g();

// long name, difficult to read, prone to silent dead code if namespace change.
if ($o 'instanceof a\b\c\d\e\f\g) {

}

// short names Easy to update all at once.
new Object();
if ($o 'instanceof Object) {

}

?>
Short name Namespaces/ShouldMakeAlias
Themes Analyze, ZendFramework

9.403. Should Make Ternary

Ternary operators are the best when assigning values to a variable.

This way, they are less verbose, compatible with assignation and easier to read.

<?php
    // verbose if then structure
    if ($a == 3) {
        $b = 2;
    } else {
        $b = 3;
    }

    // compact ternary call
    $b = ($a == 3) ? 2 : 3;

    // verbose if then structure
    // Works with short assignations and simple expressions
    if ($a != 3) {
        $b += 2 - $a * 4;
    } else {
        $b += 3;
    }

    // compact ternary call
    $b += ($a != 3) ? 2 - $a * 4 : 3;

?>