Completed
Pull Request — master (#221)
by personal
04:09
created

LackOfCohesionOfMethods::traverse()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 7
nc 3
nop 1
dl 0
loc 13
rs 9.4285
c 1
b 0
f 0
1
<?php
2
3
/*
4
 * (c) Jean-François Lépine <https://twitter.com/Halleck45>
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
10
namespace Hal\Metrics\Complexity\Structural\LCOM;
11
use Hal\Component\Reflected\Klass;
12
use Hal\Component\Tree\Graph;
13
use Hal\Component\Tree\Node;
14
use Hal\Metrics\ClassMetric;
15
16
/**
17
 * Calculates lack of cohesion method
18
 *
19
 * @author Jean-François Lépine <https://twitter.com/Halleck45>
20
 */
21
class LackOfCohesionOfMethods implements ClassMetric {
22
23
24
    /**
25
     * @param Klass $class
26
     * @return Result
27
     */
28
    public function calculate(Klass $class) {
29
30
        $graph = new Graph();
31
32
        // attributes in graph are prefixed with '_attr_' string
33
        foreach($class->getMethods() as $method) {
34
35
            // avoid getters and setters
36
            if($method->isGetter() ||$method->isSetter()) {
37
                continue;
38
            }
39
40
            if(null === ($from = $graph->get($method->getName()))) {
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $from is correct as $graph->get($method->getName()) (which targets Hal\Component\Tree\Graph::get()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
41
                $from = new Node($method->getName());
42
                $graph->insert($from);
43
            }
44
45
            // calls
46
            foreach($method->getCalls() as $call) {
47
48
                if(!$call->isItself()) {
49
                    continue;
50
51
                }
52
53
                if(null === ($to = $graph->get($call->getMethodName()))) {
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $to is correct as $graph->get($call->getMethodName()) (which targets Hal\Component\Tree\Graph::get()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
54
                    $to = new Node($call->getMethodName());
55
                    $graph->insert($to);
56
                }
57
                $graph->addEdge($from, $to);
0 ignored issues
show
Bug introduced by
It seems like $from defined by $graph->get($method->getName()) on line 40 can be null; however, Hal\Component\Tree\Graph::addEdge() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
Bug introduced by
It seems like $to defined by $graph->get($call->getMethodName()) on line 53 can be null; however, Hal\Component\Tree\Graph::addEdge() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
58
            }
59
60
            // attributes
61
            foreach($method->getTokens() as $token) {
62
                if(preg_match('!\$this\->(\w+)$!', $token, $matches)) {
63
                    list(, $attribute) = $matches;
64
65
                    if(null === ($to = $graph->get('_attr_' . $attribute))) {
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $to is correct as $graph->get('_attr_' . $attribute) (which targets Hal\Component\Tree\Graph::get()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
66
                        $to = new Node('_attr_' . $attribute);
67
                        $graph->insert($to);
68
                    }
69
                    $graph->addEdge($from, $to);
0 ignored issues
show
Bug introduced by
It seems like $from defined by $graph->get($method->getName()) on line 40 can be null; however, Hal\Component\Tree\Graph::addEdge() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
Bug introduced by
It seems like $to defined by $graph->get('_attr_' . $attribute) on line 65 can be null; however, Hal\Component\Tree\Graph::addEdge() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
70
                }
71
            }
72
73
        }
74
75
        // iterate over nodes, and count paths
76
        $paths = 0;
77
        foreach($graph->all() as $node) {
78
            $paths += $this->traverse($node);
79
        }
80
81
        $result = new Result;
82
        $result->setLcom($paths);
83
        return $result;
84
85
    }
86
87
88
    /**
89
     * Traverse node, and return 1 if node has not been visited yet
90
     *
91
     * @param Node $node
92
     * @return int
93
     */
94
    private function traverse(Node $node)
95
    {
96
        if($node->visited) {
97
            return 0;
98
        }
99
        $node->visited = true;
100
101
        foreach($node->getAdjacents() as $adjacent) {
102
            $this->traverse($adjacent);
103
        }
104
105
        return 1;
106
    }
107
}
108
109
110
111
112
113