Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
/**
3
 * PHPUnit
4
 *
5
 * Copyright (c) 2002-2010, Sebastian Bergmann <sb@sebastian-bergmann.de>.
6
 * All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 *
12
 *   * Redistributions of source code must retain the above copyright
13
 *     notice, this list of conditions and the following disclaimer.
14
 *
15
 *   * Redistributions in binary form must reproduce the above copyright
16
 *     notice, this list of conditions and the following disclaimer in
17
 *     the documentation and/or other materials provided with the
18
 *     distribution.
19
 *
20
 *   * Neither the name of Sebastian Bergmann nor the names of his
21
 *     contributors may be used to endorse or promote products derived
22
 *     from this software without specific prior written permission.
23
 *
24
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35
 * POSSIBILITY OF SUCH DAMAGE.
36
 *
37
 * @category   Testing
38
 * @package    PHPUnit
39
 * @author     Sebastian Bergmann <sb@sebastian-bergmann.de>
40
 * @copyright  2002-2010 Sebastian Bergmann <sb@sebastian-bergmann.de>
41
 * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
42
 * @link       http://www.phpunit.de/
43
 * @since      File available since Release 3.2.0
44
 */
45
 
46
require_once 'PHPUnit/Util/Class.php';
47
require_once 'PHPUnit/Util/Metrics.php';
48
require_once 'PHPUnit/Util/Filter.php';
49
 
50
PHPUnit_Util_Filter::addFileToFilter(__FILE__, 'PHPUNIT');
51
 
52
/**
53
 * Class-Level Metrics.
54
 *
55
 * @category   Testing
56
 * @package    PHPUnit
57
 * @author     Sebastian Bergmann <sb@sebastian-bergmann.de>
58
 * @copyright  2002-2010 Sebastian Bergmann <sb@sebastian-bergmann.de>
59
 * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
60
 * @version    Release: 3.4.15
61
 * @link       http://www.phpunit.de/
62
 * @since      Class available since Release 3.2.0
63
 */
64
class PHPUnit_Util_Metrics_Class extends PHPUnit_Util_Metrics
65
{
66
    protected $aif           = 0;
67
    protected $ahf           = 0;
68
    protected $ca            = 0;
69
    protected $ce            = 0;
70
    protected $coverage      = 0;
71
    protected $dit           = 0;
72
    protected $i             = 0;
73
    protected $impl          = 0;
74
    protected $loc           = 0;
75
    protected $locExecutable = 0;
76
    protected $locExecuted   = 0;
77
    protected $mif           = 0;
78
    protected $mhf           = 0;
79
    protected $noc           = 0;
80
    protected $pf            = 0;
81
    protected $vars          = 0;
82
    protected $varsNp        = 0;
83
    protected $varsI         = 0;
84
    protected $wmc           = 0;
85
    protected $wmcNp         = 0;
86
    protected $wmcI          = 0;
87
 
88
    protected $project;
89
    protected $package = '';
90
    protected $class;
91
    protected $methods = array();
92
    protected $inheritedMethods = array();
93
    protected $dependencies = array();
94
    protected $publicMethods = 0;
95
 
96
    protected static $cache = array();
97
    protected static $nocCache = array();
98
 
99
    /**
100
     * Constructor.
101
     *
102
     * @param  ReflectionClass $class
103
     * @param  array           $codeCoverage
104
     */
105
    protected function __construct(ReflectionClass $class, &$codeCoverage = array())
106
    {
107
        $this->class = $class;
108
 
109
        $className = $class->getName();
110
 
111
        $packageInformation = PHPUnit_Util_Class::getPackageInformation(
112
          $className, $class->getDocComment()
113
        );
114
 
115
        if (!empty($packageInformation['fullPackage'])) {
116
            $this->package = $packageInformation['fullPackage'];
117
        }
118
 
119
        $this->setCoverage($codeCoverage);
120
 
121
        $this->dit  = count(PHPUnit_Util_Class::getHierarchy($class->getName())) - 1;
122
        $this->impl = count($class->getInterfaces());
123
 
124
        foreach ($this->class->getMethods() as $method) {
125
            if ($method->getDeclaringClass()->getName() == $className) {
126
                $this->methods[$method->getName()] = PHPUnit_Util_Metrics_Function::factory($method, $codeCoverage);
127
            } else {
128
                $this->inheritedMethods[$method->getName()] = PHPUnit_Util_Metrics_Function::factory($method, $codeCoverage);
129
            }
130
        }
131
 
132
        $this->calculateAttributeMetrics();
133
        $this->calculateMethodMetrics();
134
        $this->calculateNumberOfChildren();
135
        $this->calculatePolymorphismFactor();
136
        $this->calculateDependencies();
137
    }
138
 
139
    /**
140
     * Factory.
141
     *
142
     * @param  ReflectionClass $class
143
     * @param  array           $codeCoverage
144
     * @return PHPUnit_Util_Metrics_Class
145
     */
146
    public static function factory(ReflectionClass $class, &$codeCoverage = array())
147
    {
148
        $className = $class->getName();
149
 
150
        if (!isset(self::$cache[$className])) {
151
            self::$cache[$className] = new PHPUnit_Util_Metrics_Class($class, $codeCoverage);
152
        }
153
 
154
        else if (!empty($codeCoverage) && self::$cache[$className]->getCoverage() == 0) {
155
            self::$cache[$className]->setCoverage($codeCoverage);
156
        }
157
 
158
        return self::$cache[$className];
159
    }
160
 
161
    /**
162
     * @param  array $codeCoverage
163
     */
164
    public function setCoverage(array &$codeCoverage)
165
    {
166
        if (!empty($codeCoverage)) {
167
            $this->calculateCodeCoverage($codeCoverage);
168
 
169
            foreach ($this->methods as $method) {
170
                $method->setCoverage($codeCoverage);
171
            }
172
        }
173
    }
174
 
175
    /**
176
     * @param  PHPUnit_Util_Metrics_Project $project
177
     */
178
    public function setProject(PHPUnit_Util_Metrics_Project $project)
179
    {
180
        $this->project = $project;
181
 
182
        $this->ca = 0;
183
        $this->ce = 0;
184
        $this->i  = 0;
185
    }
186
 
187
    /**
188
     * Returns the class.
189
     *
190
     * @return ReflectionClass
191
     */
192
    public function getClass()
193
    {
194
        return $this->class;
195
    }
196
 
197
    /**
198
     * Returns the package of this class.
199
     *
200
     * @return string
201
     */
202
    public function getPackage()
203
    {
204
        return $this->package;
205
    }
206
 
207
    /**
208
     * Returns the methods of this class.
209
     *
210
     * @return array
211
     */
212
    public function getMethods()
213
    {
214
        return $this->methods;
215
    }
216
 
217
    /**
218
     * Returns the names of the classes this class depends on.
219
     *
220
     * @return array
221
     */
222
    public function getDependencies()
223
    {
224
        return $this->dependencies;
225
    }
226
 
227
    /**
228
     * Lines of Code (LOC).
229
     *
230
     * @return int
231
     */
232
    public function getLoc()
233
    {
234
        return $this->loc;
235
    }
236
 
237
    /**
238
     * Executable Lines of Code (ELOC).
239
     *
240
     * @return int
241
     */
242
    public function getLocExecutable()
243
    {
244
        return $this->locExecutable;
245
    }
246
 
247
    /**
248
     * Executed Lines of Code.
249
     *
250
     * @return int
251
     */
252
    public function getLocExecuted()
253
    {
254
        return $this->locExecuted;
255
    }
256
 
257
    /**
258
     * Returns the Number of Public Methods of the class.
259
     *
260
     * @return integer
261
     */
262
    public function getPublicMethods()
263
    {
264
        return $this->publicMethods;
265
    }
266
 
267
    /**
268
     * Returns the Attribute Inheritance Factor (AIF) for the class.
269
     *
270
     * @return integer
271
     * @see    http://www.aivosto.com/project/help/pm-oo-mood.html
272
     */
273
    public function getAIF()
274
    {
275
        return $this->aif;
276
    }
277
 
278
    /**
279
     * Returns the Attribute Hiding Factor (AHF) for the class.
280
     *
281
     * @return integer
282
     * @see    http://www.aivosto.com/project/help/pm-oo-mood.html
283
     */
284
    public function getAHF()
285
    {
286
        return $this->ahf;
287
    }
288
 
289
    /**
290
     * Returns the Afferent Couplings (Ca) for the class.
291
     *
292
     * The number of other classes that depend upon a class is an indicator of
293
     * the class' responsibility.
294
     *
295
     * @return integer
296
     */
297
    public function getCa()
298
    {
299
        $this->calculateDependencyMetrics();
300
 
301
        return $this->ca;
302
    }
303
 
304
    /**
305
     * Returns the Efferent Couplings (Ce) for the class.
306
     *
307
     * The number of other classes that the class depends upon is an indicator
308
     * of the class' independence.
309
     *
310
     * @return integer
311
     */
312
    public function getCe()
313
    {
314
        $this->calculateDependencyMetrics();
315
 
316
        return $this->ce;
317
    }
318
 
319
    /**
320
     * Returns the Class Size (CSZ) of the class.
321
     *
322
     * @return integer
323
     * @see    http://www.aivosto.com/project/help/pm-oo-misc.html
324
     */
325
    public function getCSZ()
326
    {
327
        return count($this->methods) + $this->vars;
328
    }
329
 
330
    /**
331
     * Returns the Class Interface Size (CIS) of the class.
332
     *
333
     * @return integer
334
     * @see    http://www.aivosto.com/project/help/pm-oo-misc.html
335
     */
336
    public function getCIS()
337
    {
338
        return $this->publicMethods + $this->varsNp;
339
    }
340
 
341
    /**
342
     * Returns the Code Coverage for the class.
343
     *
344
     * @return float
345
     */
346
    public function getCoverage()
347
    {
348
        return $this->coverage;
349
    }
350
 
351
    /**
352
     * Returns the Depth of Inheritance Tree (DIT) for the class.
353
     *
354
     * @return integer
355
     * @see    http://www.aivosto.com/project/help/pm-oo-ck.html
356
     */
357
    public function getDIT()
358
    {
359
        return $this->dit;
360
    }
361
 
362
    /**
363
     * Returns the Instability (I) for the class.
364
     *
365
     * The ratio of efferent coupling (Ce) to total coupling (Ce + Ca) such that
366
     * I = Ce / (Ce + Ca). This metric is an indicator of the class' resilience
367
     * to change.
368
     *
369
     * The range for this metric is 0 to 1, with I=0 indicating a completely
370
     * stable class and I=1 indicating a completely instable class.
371
     *
372
     * @return float
373
     */
374
    public function getI()
375
    {
376
        $this->calculateDependencyMetrics();
377
 
378
        return $this->i;
379
    }
380
 
381
    /**
382
     * Returns the Number of Interfaces Implemented by the class (IMPL).
383
     *
384
     * @return integer
385
     * @see    http://www.aivosto.com/project/help/pm-oo-misc.html
386
     */
387
    public function getIMPL()
388
    {
389
        return $this->impl;
390
    }
391
 
392
    /**
393
     * Returns the Method Inheritance Factor (MIF) for the class.
394
     *
395
     * @return float
396
     * @see    http://www.aivosto.com/project/help/pm-oo-mood.html
397
     */
398
    public function getMIF()
399
    {
400
        return $this->mif;
401
    }
402
 
403
    /**
404
     * Returns the Method Hiding Factor (MHF) for the class.
405
     *
406
     * @return float
407
     * @see    http://www.aivosto.com/project/help/pm-oo-mood.html
408
     */
409
    public function getMHF()
410
    {
411
        return $this->mhf;
412
    }
413
 
414
    /**
415
     * Returns the Number of Children (NOC) for the class.
416
     *
417
     * @return integer
418
     * @see    http://www.aivosto.com/project/help/pm-oo-ck.html
419
     */
420
    public function getNOC()
421
    {
422
        return $this->noc;
423
    }
424
 
425
    /**
426
     * Returns the Polymorphism Factor (PF) for the class.
427
     *
428
     * @return float
429
     * @see    http://www.aivosto.com/project/help/pm-oo-mood.html
430
     */
431
    public function getPF()
432
    {
433
        return $this->pf;
434
    }
435
 
436
    /**
437
     * Returns the Number of Variables (VARS) defined by the class.
438
     *
439
     * @return integer
440
     * @see    http://www.aivosto.com/project/help/pm-oo-misc.html
441
     */
442
    public function getVARS()
443
    {
444
        return $this->vars;
445
    }
446
 
447
    /**
448
     * Returns the Number of Non-Private Variables (VARSnp) defined by the class.
449
     *
450
     * @return integer
451
     * @see    http://www.aivosto.com/project/help/pm-oo-misc.html
452
     */
453
    public function getVARSnp()
454
    {
455
        return $this->varsNp;
456
    }
457
 
458
    /**
459
     * Returns the Number of Variables (VARSi) defined and inherited by the class.
460
     *
461
     * @return integer
462
     * @see    http://www.aivosto.com/project/help/pm-oo-misc.html
463
     */
464
    public function getVARSi()
465
    {
466
        return $this->varsI;
467
    }
468
 
469
    /**
470
     * Returns the Weighted Methods Per Class (WMC) for the class.
471
     *
472
     * @return integer
473
     * @see    http://www.aivosto.com/project/help/pm-oo-ck.html
474
     */
475
    public function getWMC()
476
    {
477
        return $this->wmc;
478
    }
479
 
480
    /**
481
     * Returns the Weighted Non-Private Methods Per Class (WMCnp) for the class.
482
     *
483
     * @return integer
484
     * @see    http://www.aivosto.com/project/help/pm-oo-misc.html
485
     */
486
    public function getWMCnp()
487
    {
488
        return $this->wmcNp;
489
    }
490
 
491
    /**
492
     * Returns the Weighted Inherited Methods Per Class (WMCi) for the class.
493
     *
494
     * @return integer
495
     * @see    http://www.aivosto.com/project/help/pm-oo-misc.html
496
     */
497
    public function getWMCi()
498
    {
499
        return $this->wmcI;
500
    }
501
 
502
    /**
503
     * Calculates the Attribute Inheritance Factor (AIF) and
504
     * Attribute Hiding Factor (AHF) metrics for the class.
505
     *
506
     */
507
    protected function calculateAttributeMetrics()
508
    {
509
        $attributes          = 0;
510
        $hiddenAttributes    = 0;
511
        $inheritedAttributes = 0;
512
 
513
        foreach ($this->class->getProperties() as $attribute) {
514
            if ($attribute->isPublic()) {
515
                $this->varsNp++;
516
            } else {
517
                $hiddenAttributes++;
518
            }
519
 
520
            if ($attribute->getDeclaringClass()->getName() == $this->class->getName()) {
521
                $this->vars++;
522
            } else {
523
                $inheritedAttributes++;
524
            }
525
 
526
            $this->varsI++;
527
            $attributes++;
528
        }
529
 
530
        if ($attributes > 0) {
531
            $this->aif = (100 * $inheritedAttributes) / $attributes;
532
            $this->ahf = (100 * $hiddenAttributes) / $attributes;
533
        }
534
    }
535
 
536
    /**
537
     * Calculates the Method Inheritance Factor (MIF)
538
     * Method Hiding Factor (MHF), Weighted Methods Per Class (WMC),
539
     * Weighted Non-Private Methods Per Class (WMCnp), and
540
     * Weighted Inherited Methods Per Class (WMCi) metrics for the class.
541
     *
542
     */
543
    protected function calculateMethodMetrics()
544
    {
545
        $numMethods       = 0;
546
        $hiddenMethods    = 0;
547
        $inheritedMethods = 0;
548
 
549
        $methods = array_merge($this->methods, $this->inheritedMethods);
550
 
551
        foreach ($methods as $method) {
552
            $ccn = $method->getCCN();
553
 
554
            if ($method->getMethod()->getDeclaringClass()->getName() == $this->class->getName()) {
555
                $this->wmc += $ccn;
556
 
557
                if ($method->getMethod()->isPublic()) {
558
                    $this->publicMethods++;
559
                    $this->wmcNp += $ccn;
560
                }
561
            } else {
562
                $inheritedMethods++;
563
            }
564
 
565
            if (!$method->getMethod()->isPublic()) {
566
                $hiddenMethods++;
567
            }
568
 
569
            $this->wmcI += $ccn;
570
            $numMethods++;
571
        }
572
 
573
        if ($numMethods > 0) {
574
            $this->mif = (100 * $inheritedMethods) / $numMethods;
575
            $this->mhf = (100 * $hiddenMethods) / $numMethods;
576
        }
577
    }
578
 
579
    /**
580
     * Calculates the Number of Children (NOC) metric for the class.
581
     *
582
     */
583
    protected function calculateNumberOfChildren()
584
    {
585
        $className = $this->class->getName();
586
 
587
        if (!isset(self::$nocCache[$className])) {
588
            self::$nocCache = array();
589
        }
590
 
591
        if (empty(self::$nocCache)) {
592
            foreach (get_declared_classes() as $_className) {
593
                $class  = new ReflectionClass($_className);
594
                $parent = $class->getParentClass();
595
 
596
                if ($parent !== FALSE) {
597
                    $parentName = $parent->getName();
598
 
599
                    if (isset(self::$nocCache[$parentName])) {
600
                        self::$nocCache[$parentName]++;
601
                    } else {
602
                        self::$nocCache[$parentName] = 1;
603
                    }
604
                }
605
            }
606
        }
607
 
608
        if (isset(self::$nocCache[$className])) {
609
            $this->noc = self::$nocCache[$className];
610
        }
611
    }
612
 
613
    /**
614
     * Calculates the Polymorphism Factor (PF) metric for the class.
615
     *
616
     * @param  ReflectionClass $class
617
     */
618
    protected function calculatePolymorphismFactor()
619
    {
620
        $parentClass = $this->class->getParentClass();
621
 
622
        if ($parentClass !== FALSE) {
623
            $overridableMethods = array();
624
 
625
            foreach ($parentClass->getMethods() as $method) {
626
                if (!$method->isPrivate() && !$method->isFinal() && !$method->isAbstract()) {
627
                    $overridableMethods[] = $method->getName();
628
                }
629
            }
630
 
631
            if (!empty($overridableMethods)) {
632
                $overriddenMethods = 0;
633
 
634
                foreach ($this->class->getMethods() as $method) {
635
                    if ($method->getDeclaringClass()->getName() == $this->class->getName()) {
636
                        $methodName = $method->getName();
637
 
638
                        if (in_array($methodName, $overridableMethods)) {
639
                            $overriddenMethods++;
640
                        }
641
                    }
642
                }
643
 
644
                $this->pf = (100 * $overriddenMethods) / count($overridableMethods);
645
            }
646
        }
647
    }
648
 
649
    /**
650
     * Calculates the Code Coverage for the class.
651
     *
652
     * @param  array $codeCoverage
653
     */
654
    protected function calculateCodeCoverage(&$codeCoverage)
655
    {
656
        $statistics = PHPUnit_Util_CodeCoverage::getStatistics(
657
          $codeCoverage,
658
          $this->class->getFileName(),
659
          $this->class->getStartLine(),
660
          $this->class->getEndLine()
661
        );
662
 
663
        $this->coverage      = $statistics['coverage'];
664
        $this->loc           = $statistics['loc'];
665
        $this->locExecutable = $statistics['locExecutable'];
666
        $this->locExecuted   = $statistics['locExecuted'];
667
    }
668
 
669
    /**
670
     * Calculates the dependencies for this class.
671
     *
672
     */
673
    protected function calculateDependencies()
674
    {
675
        $parent = $this->class->getParentClass();
676
 
677
        if ($parent && $parent->isUserDefined() && !in_array($parent->getName(), $this->dependencies)) {
678
            $this->dependencies[] = $parent->getName();
679
        }
680
 
681
        $interfaces = $this->class->getInterfaces();
682
 
683
        foreach ($interfaces as $interface) {
684
            if ($interface->isUserDefined() && !in_array($interface->getName(), $this->dependencies)) {
685
                $this->dependencies[] = $interface->getName();
686
            }
687
        }
688
 
689
        $methods = array_merge($this->methods, $this->inheritedMethods);
690
 
691
        foreach ($methods as $method) {
692
            foreach ($method->getDependencies() as $dependency) {
693
                if (!in_array($dependency, $this->dependencies)) {
694
                    $this->dependencies[] = $dependency;
695
                }
696
            }
697
        }
698
    }
699
 
700
    /**
701
     * Calculates the dependency-based metrics for this class.
702
     *
703
     */
704
    protected function calculateDependencyMetrics()
705
    {
706
        if ($this->ca == 0 && $this->ce == 0 && $this->i == 0) {
707
            $className    = $this->class->getName();
708
            $dependencies = $this->project->getDependencies();
709
 
710
            foreach ($dependencies[$className] as $dependency) {
711
                if ($dependency > 0) {
712
                    $this->ce++;
713
                }
714
            }
715
 
716
            unset($dependencies[$className]);
717
 
718
            foreach ($dependencies as $_className => $_dependencies) {
719
                if ($_dependencies[$className] > 0) {
720
                    $this->ca++;
721
                }
722
            }
723
 
724
            $sum = $this->ce + $this->ca;
725
 
726
            if ($sum > 0) {
727
                $this->i = $this->ce / $sum;
728
            }
729
        }
730
    }
731
}
732
?>