Completed
Pull Request — master (#254)
by Enrico
14:10 queued 09:31
created

DivisionFromZero   A

Complexity

Total Complexity 5

Size/Duplication

Total Lines 47
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 5

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 47
ccs 20
cts 20
cp 1
rs 10
c 1
b 0
f 0
wmc 5
lcom 0
cbo 5

2 Methods

Rating   Name   Duplication   Size   Complexity  
B pass() 0 22 4
A getRegister() 0 9 1
1
<?php
2
3
namespace PHPSA\Analyzer\Pass\Expression;
4
5
use PhpParser\Node\Expr;
6
use PHPSA\Analyzer\Helper\DefaultMetadataPassTrait;
7
use PHPSA\Analyzer\Pass\AnalyzerPassInterface;
8
use PHPSA\Context;
9
10
class DivisionFromZero implements AnalyzerPassInterface
11
{
12
    use DefaultMetadataPassTrait;
13
14
    const DESCRIPTION = 'Checks for division from 0. For example: `0/$x`, `false%$x`';
15
16
    /**
17
     * @param Expr $expr
18
     * @param Context $context
19
     * @return bool
20
     */
21 102
    public function pass(Expr $expr, Context $context)
22
    {
23 102
        $compiler = $context->getExpressionCompiler();
24
25 102
        if ($expr instanceof Expr\AssignOp) {
26 30
            $left = $compiler->compile($expr->var);
27 102
        } elseif ($expr instanceof Expr\BinaryOp) {
28 73
            $left = $compiler->compile($expr->left);
29 73
        }
30
31 102
        if ($left->getValue() == 0) {
0 ignored issues
show
Bug introduced by
The variable $left does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
32 19
            $context->notice(
33 19
                'division_from_zero',
34 19
                "You are trying to divide from zero",
35
                $expr
36 19
            );
37
38 19
            return true;
39
        }
40
        
41 84
        return false;
42
    }
43
44
    /**
45
     * @return array
46
     */
47 1
    public function getRegister()
48
    {
49
        return [
50 1
            Expr\BinaryOp\Div::class,
51 1
            Expr\BinaryOp\Mod::class,
52 1
            Expr\AssignOp\Div::class,
53 1
            Expr\AssignOp\Mod::class,
54 1
        ];
55
    }
56
}
57