hunt for dead code

58
Lorem Ipsum Dolor The hunt for dead code PHP South Africa

Upload: damien-seguy-

Post on 26-Jan-2017

45 views

Category:

Technology


0 download

TRANSCRIPT

Lorem Ipsum Dolor

The hunt for dead code

PHP South Africa

Agenda

❖ What is dead code

❖ Classic/PHP dead code

❖ Removing dead structures

Speaker

❖ CTO Exakat

❖ Doing PHP on every continents

❖ Static code analysis for PHP

Dead code

❖ Code that is never used

❖ Data never delivered to the user

❖ Opposite to :

PHP Fatal error: Uncaught Error: Call to undefined function foo()

Dead code

<?php

function foo() {}

$y = rand(0, 12);

echo 'two';

?>

if ($y == 2) {    echo 'two'; } 

?>

Dead code<?php 

class A implements B {}

interface B {}

?>

<?php interface B implementedBy A,B,C {}

class A {}

?>

Wouldn't it be better to hunt dead code to write this?

Dead code

❖ PHP base install

❖ 766 functions

❖ 92 classes

❖ 1024 constants

❖ Avoid compiling too many PHP extensions

❖ Use disable_functions

Why remove?

❖ Larger code source

❖ Less maintainable code

❖ Dead code is often maintained

❖ Slower code

❖ Dead code grows over time

Why keep dead code?

❖ No one was ever fired to keep dead code

❖ Why fix something that isn't broken

❖ All tests for this feature are OK

❖ Other part of the code depends on it

❖ Code base always grows organically

❖ No time for that!

How to remove dead code

❖ Spot the original code

❖ Check for its usage

❖ Remove usages one by one

❖ Remove the original code

3 types of dead code

❖ Classic dead code

❖ PHP stealth dead code

❖ Structural dead code

Classic dead code

Dead code in any language

Unreachable code

<?php

if (false) {    print_r($variable); }

if (0) {     // Huge piece of code with bug    // or unfinished new feature } ?>

❖ Classic debug

Unreachable code

<?php

function foo($bar) {    for($i = 0; $i < 10; $i++) {      $bar *= 2;             exit; // or die      $bar += 1;    } }

?>

❖ Classic unreachable

Unreachable code

<?php

function foo($bar) {    for($i = 0; $i < 10; $i++) {     $bar *= 2;             continue;      $bar += 1;    } }

?>

❖ Classic unreachable

Unreachable code

<?php

function foo($bar) {    for($i = 0; $i < 10; $i++) {      $bar *= 2;             break 1;      $bar += 1;    } }

?>

❖ Classic unreachable

Unreachable code

<?php

function foo($bar) {    $bar *= 2;        return $bar;

   $bar += 1;    return $bar; }

?>

❖ Classic unreachable

Unreachable code

<?php

$bar *= 2; goto END: $bar += 1;        exit;  end: print $bar;

?>

❖ Classic unreachable

Unreachable code

<?php

$bar = 2; goto END;   class X {    const ONE = 1; }

exit;  END: print $bar . X::ONE; ?>

❖ Classic unreachable

❖ But definitions are still accessible

Useless variables<?php 

$usedOnce = "Hello world";

?>

❖ The mythical 'used once' variable

❖ 75% repo has this kind of variable

❖ Global or local to functions

❖ Mass import $_GET/_POST

<?php 

echo $alsoUsedOnce;

?>

Useless variables

<?php  

function foo() {   $a = "Hello world";    //more code    $a = "Hello universe";    //more code   $a .= " and the world";  }

?>

❖ Written only variables

❖ Inside a scope

❖ Read-only is better but worth a check

PHP skeletons in the closet

Default clause in switch()<?php   

switch($x) {        case '1' :             break;        default :             break;        default :             break;        case '2' :             break;    }   

❖ PHP 7.0+ : Fatal error

❖ 'case' order is "not" important

Multiple cases ?

❖ Switch() uses ==

❖ Transtyping happens

switch($x) {        case 1 :             break;        case 0+1 :             break;        case '1' :             break;        case true :             break;        case 1.0 :             break;        case $y :             break;    }   

Arrays index

<?php

$a = [ true  => 1,         1.0  => 2,         1.1  => 3,         4,        "1.4" => 5,        2  => 6];         print_r($a);

?>

❖ are int or strings

❖ Beware of mix between auto-indexing andfixed values Array

( [1] => 3 [2] => 6 [1.4] => 5 )

Dead code in plain sight<?php

try {    doSomething(); } catch (NotAnException $e) {

} catch (MyExxeption $e) {

} catch (\Exception $e) {

} catch (MyException $e) {

}

❖ Non Existing classes

❖ Non-Exceptions

❖ Specific to general

❖ Simply ignored

Instanceof

❖ The target class is in the current namespace

<?php

class MyClass {}

$o = new MyClass();

if ($o instanceof MyClass) {    print "Found MyClass\n"; }

?>

Instanceof

❖ The target class is in the current namespace

❖ Beware of moving classes and instanceof around

<?php

namespace { class MyClass {} }

namespace X { $o = new \MyClass();

if ($o instanceof MyClass) {     print "Found MyClass\n"; } }

?>

Instanceof

❖ Hardcoded names vsstrings classnames

namespace { class MyClass {} }

namespace X { $o = new \MyClass();

$a = '\\X\\MyClass'; if ($o instanceof $a) {     print "Found MyClass with \$a\n"; } }

Typehint

❖ Typehint are not checked either

❖ You can check type hint at execution time

<?php

class foo {}

$o = new foo();

function bar(fooo $a) {}

bar($o); ?>

PHP Fatal error: Uncaught TypeError: Argument 1 passed to bar() must be an instance of fooo, instance of foo given,

Structural dead code

Files ConstantsVariablesFunctionsClasses InterfacesTraits

Synopsis

❖ Definitions

❖ Usage

❖ Unreviewable pitfalls

❖ Dynamical calls

Structural dead code

Traits InterfacesClasses FunctionsConstantsFiles

Traits

<?php

trait t1 {    use t2; }

class c {    use t1; } ?>

Traits

❖ Used in class-'use' expression

❖ Depends on 'use' expression

❖ Used in static method call, static properties

<?php

trait t1 {    use t2; }

class c {    use t1; } ?>

Traits

❖ Easy to spot : only static calls

❖ Namespaced, aliased

❖ Trait local dependencies leads to more dead code

<?php 

use t1 as t3;

trait t1 {     use t2;  } 

class c {     use t3;  }  ?>

Traits<?php

trait t {    function setName($name) {      $this->name = $this->normalize($name);   } }

class bar {    use t;    private $name = 'none';

   function normalize($string) {} } ?>

Interfaces

<?php

interface i2 { }

interface i1 implements i2 { }

class c implements i1 { }

?>

Interfaces

❖ Used in classes

❖ Used in interfaces

❖ Used in static constants

❖ Used in instanceof, catch and type hint

<?php 

interface i2 { const konst = 3; }

interface i1 implements i2 { } 

class c implements i1 { } 

echo i2::konst;

?>

Interfaces

❖ It may end up in variables/literals

❖ It inherits from parents

<?php 

interface i2 { const konst = 3; }

interface i1 implements i2 { } 

$interfaceName = 'i2';

if ($object instanceof $interfaceName) {}

echo i1::konst;

?>

Classes

<?php

classes c1  { }

class c2 extends c1 { }

new c2();

?>

Classes

❖ Used in other classes

❖ Used in all static calls

❖ constants, properties, methods

❖ Normal calls ->

❖ Used in instanceof, catch, typehint

❖ Used in new

<?php

class c1  { }

class c2 extends c1 { }

new c2();

?>

Classes

❖ new a / new a()

❖ Dynamic calls all over the place

❖ It has special keywords : parent, self, static

<?php

class foo {    const ONE = 1;    const TWO = self::ONE + 1; }

class bar extends foo {    const THREE = parent::TWO + self::ONE; }

$class = 'bar'; $o = new \bar;

?>

Classes

❖ Circular dependencies

❖ Actually applies to traits and interfaces as well

<?php 

class foo extends bar {     const TWO = bar::ONE + 1;  } 

class bar extends foo {     const ONE = bar::ONE; } 

?>PHP Fatal error: Class 'bar' not found

Classes

❖ Vicious circular dependencies

<?php 

class foo {     const ONE = 1;     const TWO = bar::ONE + 1;  } 

class bar {     const ONE = foo::TWO; } 

echo bar::ONE;

PHP Fatal error: Uncaught Error: Cannot declare self-referencing constant 'foo::TWO' on line 12

❖ Interfaces, traits then classes

❖ Start with lowest positions, then least used

Functions

❖ Used in function calls

❖ Depends on namespaces and aliases

❖ Used in native functions like array_map()

<?php

function foo() {}

array_map('foo', $array);

?>

Constants

❖ Defined with const, define

❖ May be case-insensitive

❖ Dynamic constant()

❖ Namespaced, aliased

❖ Used in static expressions

❖ This leads to inclusion hells

<?php 

define(ONE, 1, true);

const TWO = ONE + 1; 

$constant = 'TWO'; echo constant($constant);

?>

Inclusion

❖ include/require, /_once

❖ new() because autoload

❖ Static constant, static methods calls, static property

❖ Order is important, as include also execute…

<?php 

include 'file.php';

?>

How to spot issues?

❖ Code knowledge

❖ lint

❖ Grep / Search

❖ Static analysis

❖ Logs / error_reporting

❖ Unit Tests

When to hunt dead code?❖ An every day relaxation

❖ My most productive day saw 200 classes removed

❖ trigger_error($msg, E_USER_DEPRECATED) and debug_backtrace()

❖ Bath in the energy of live code

Lorem Ipsum Dolor

Thanks!

@exakathttp://www.exakat.io/http://slideshare.net/dseguy/

Dynamic variables

<?php 

$a = 'b'; $b = 'c'; $c = 'd';

$$${$a} = '3'; echo $d;

?>

❖ Variable variables

❖ Extract()

❖ parse_str(), one arg

Unreachable code

<?php

if ($sale_price === $regular_price ||  $sale_price !== $price) {    print_r($variable); }

?>

Unreachable code

$sale_price $regular $price results

$regular 1 1 1

$price 0 0 0

All other values

0 1 1

($sale_price === $regular_price|| $sale_price !== $price)

Constant Property Method

Class X X X

Interface X X

Traits X X