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

LackOfCohesionOfMethods   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 87
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 6

Importance

Changes 3
Bugs 0 Features 0
Metric Value
dl 0
loc 87
rs 10
c 3
b 0
f 0
wmc 15
lcom 0
cbo 6

2 Methods

Rating   Name   Duplication   Size   Complexity  
C calculate() 0 58 12
A traverse() 0 13 3
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