SlideShare una empresa de Scribd logo
1 de 47
Descargar para leer sin conexión
Dealing with
Legacy PHP
Applications

Clinton R. Nixon
crnixon@gmail.com
What is a legacy
application?


    Code you didn't write


    Code you wouldn't write


    Untested code


    Code with competing visions

What do we do with
legacy code?

We refactor!

Refactoring is safely changing the
implementation of code without
changing the behavior of code.
Bad code smells
What are some specific problems in legacy PHP code?
    No separation between PHP and HTML


    Lots of requires, few method calls


    Global variables

No separation between PHP and HTML
<h1>Orders</h1>
<?php
$account = new Account($account_id);
$account->loadOrders();
foreach ($account->getOrders() as $order) {
   echo '<h2>' . $order['id'] . '</h2>';
   echo '<p>Status: ' .
     lookup_status($order['status_id']) . '<br />;
   echo 'Total: ';
   $total = array_reduce($order['purchases'],
     create_function('$a, $b', '$a += $b; return $a'));
   echo $total . '</p>';
}
?>
Separating controllers and views
    Even without a solid MVC architecture, this helps


    You can do this in several safe and easy steps


    You absolutely will find pain points

Why do I need to do this?
    Your code complexity will increase


    echo isn't as fun as it looks


    You will find hidden bugs and mistakes

The simplest view class
class View {
    protected static $VIEW_PATH = '/wherever/views/';

    public function assign($name, $value) {
       return $this->$name = $value;
    }

    public function render($filename) {
       $filename = self::$VIEW_PATH . $filename;
       if (is_file($filename)) {
          ob_start();
          include($filename);
          return ob_get_clean();
       }
    }
}
Obvious improvements to make
    Error handling


    Assignment by reference


    Changing view path


    Display convenience method


    Use-specific subclasses with helper methods

The separation process
    Gather all your code


    Sift and separate controller from view code


    Assign variables to the view object


    Change all variable references in the view code


    Split the files


    Find duplicated views

The rules of view code
Allowed:
      Control structures
  

      echo, or <?= $var ?>
  

      Display-specific functions, never nested
  

Not allowed:
      Assignment
  

      Other function calls
  
Gather and sift code
    The step you won't like: gather all code for this controller


    Wipe brow


    Draw a line at the top of the code


    Move controller code above this line, fixing as necessary


        At this point, everything is view code
    
Code gathered
<?php // View code goes below here ?>
<h1>Orders</h1>
<?php
$account = new Account($account_id);
$account->loadOrders();
foreach ($account->getOrders() as $order) {
   echo '<h2>' . $order['id'] . '</h2>';
   echo '<p>Status: ' .
     lookup_status($order['status_id']) . '<br />;
   echo 'Total: ';
   $total = array_reduce($order['purchases'],
     create_function('$a, $b', '$a += $b; return $a'));
   echo $total . '</p>';
}
?>
Some controller code moved
<?php
$account = new Account($account_id);
$account->loadOrders();
?>
<?php // View code goes below here ?>
<h1>Orders</h1>
<?php foreach ($account->getOrders() as $order) { ?>
   <h2><?= $order['id'] ?></h2>
   <p>Status: <?= lookup_status($order['status_id'])
   <br />
   Total:
   <?= array_reduce($order['purchases'],
     create_function('$a, $b', '$a += $b; return $a'))
   ?>
   </p>
<?php } ?>
Alternative control structures
<?php if ($foo): ?>
...
<?php endif; ?>


<?php foreach ($this as $that): ?>
...
<?php endforeach; ?>
Using alternative control structures
<?php
$account = new Account($account_id);
$account->loadOrders();
?>
<?php // View code goes below here ?>
<h1>Orders</h1>
<?php foreach ($account->getOrders() as $order): ?>
   <h2><?= $order['id'] ?></h2>
   <p>Status: <?= lookup_status($order['status_id']) ?>
   <br />
   Total:
   <?= array_reduce($order['purchases'],
     create_function('$a, $b', '$a += $b; return $a')) ?>
   </p>
<?php endforeach; ?>
A frustrating problem
 <?php foreach ($account->getOrders() as $order): ?>
   <h2><?= $order['id'] ?></h2>
   <p>Status: <?= lookup_status($order['status_id'])
   ?>
   <br />
   Total:
   <?= array_reduce($order['purchases'],
   create_function('$a, $b', '$a += $b; return $a'))
   ?>
   </p>
 <?php endforeach; ?>
Dealing with this problem
There are two approaches.
    You can create a new array of variables for your view.


    Or, you can encapsulate this logic in an object.

Our new order object
<?php
class Order {
  ...
  public function getStatus() {
    return lookup_status($this->getStatusId());
  }

     public function getTotal() {
       return array_reduce($this->getPurchases(),
         create_function('$a, $b', '$a += $b; return $a'));
     }
}
?>
Logic removed from view code
<?php
$account = new Account($account_id);
$account->loadOrders();
$orders = $account->getOrders();
?>
<?php // View code goes below here ?>
<h1>Orders</h1>
<?php foreach ($orders as $order): ?>
   <h2><?= $order->getId() ?></h2>
   <p>Status: <?= $order->getStatus() ?>
   <br />
   Total: <?= $order->getTotal() ?>
   </p>
<?php endforeach; ?>
Change all variables to
view object variables
    Assign variables to the view object.


    $view->assign('foo', $foo);
    One-by-one, change variables in view code.


    Test to convince yourself.


    You will probably iterate back to the previous step.


    Document inputs to the view.

View object created
<?php
$account = new Account($account_id);
$account->loadOrders();
$orders = $account->getOrders();
$view = new View();
$view->assign('orders', $orders);
?>
<?php // View code goes below here ?>
<h1>Orders</h1>
<?php foreach ($view->orders as $order): ?>
   <h2><?= $order->getId() ?></h2>
   <p>Status: <?= $order->getStatus() ?>
   <br />
   Total: <?= $order->getTotal() ?>
   </p>
<?php endforeach; ?>
Separate the files
    Create a new file for the view code.


    Important! Search and replace $view with $this.


    Test one more time.

Our two files
<?php
$account = new Account($account_id);
$account->loadOrders();
$orders = $account->getOrders();
$view = new View();
$view->assign('orders', $orders);
$view->display('orders.tpl');
?>

<h1>Orders</h1>
<?php foreach ($this->orders as $order): ?>
  <h2><?= $order->getId() ?></h2>
  <p>Status: <?= $order->getStatus() ?>
  <br />
  Total: <?= $order->getTotal() ?>
  </p>
<?php endforeach; ?>
Find duplicated views
    As you do this to multiple controllers, you will see

    repetition.
    There will probably be subtle differences.


    Take the time to re-work these so you can re-use view

    files.
    Note! You can include views in other views with


    $this->render('included_file.tpl');
Using nested requires
instead of function calls
<?php
require_once('db_setup_inc.php');
require_once('account_auth_inc.php');
require_once('i18n_inc.php');

echo '<h1>Orders for account #' . $account_id .
      '</h1>';

require('get_all_orders_inc.php');

...
Untangling a require web
    Require statements which call other require statements.


    Can be very complex.


    Dependent on application structure.

Important reasons to
untangle this web
    Remove unneeded complexity.


    Create less procedural code.


    Prior to PHP 5.2, require_once and include_once

    are more expensive than you would think.
    If you are requiring class definitions, and you have a

    standard file naming method, use __autoload().
The untangling process
    Identify inputs


    Identify outputs


    Wrap the file in a method


    Refactor method


    Move method to correct location

Identify inputs and outputs
    Find all variables expected to be set before this file is

    included.
    One possible way: execute this file by itself.


    Find all variables expected to be set or mutated by this

    file.
    Set variables are easy: comment out the require and

    watch the errors.
    Mutated is the set of inputs changed. Learn to search for

    these!
account_auth_inc.php
<?php
$auth_token = $_COOKIE['token'];

if ($auth_token) {
  $acct_id = $db->GetOne('SELECT acct_id FROM
    logins WHERE auth_token = ?', array($auth_token));
}
if ($acct_id) {
  $acct = new Account($acct_id);
} else {
  $acct = null;
}
$_COOKIE['token'] = gen_new_token($auth_token);
Wrap the file in a function
    Wrap the entire include in a function.


    Pass all input variables.


    Return all output variables as an array.


    And then, call that function at the bottom of the required

    file!
    This is a mess!

Function-wrapped
<?php
function account_auth($db, $auth_token) {
  if ($auth_token) {
    $acct_id = $db->GetOne('SELECT acct_id FROM
      logins WHERE auth_token = ?',
      array($auth_token));
  }
  if ($acct_id) {
    $acct = new Account($acct_id);
  } else {
    $acct = null;
  }
  return array($acct, gen_new_token($auth_token));
}
list($acct, $_COOKIE['token']) = account_auth($db,
    $_COOKIE['token']);
Refactor until complete
    Tease out the functions, or objects, inside this function.


    If you are returning a lot of data, see if it can be an

    object.
    Leave your temporary big function in place, so that your

    outside code doesn't break. Keep updating it to deal with
    your refactoring.
Moved token handling to Account
<?php
function account_auth($db, $auth_token) {
  // Instead of null, we now return an unloaded Account.
  $acct = new Account();
  if ($auth_token) {
    // SQL code from before
    $acct->loadFromToken($auth_token);
    // Token generation and cookie setting
    $acct->genNewToken($auth_token);
  }
  return $acct;
}
$acct = account_auth($db, $_COOKIE['token']);
Move to correct location
    Finally!


    Figure out where these functions or objects should live in

    your application.
    Move them there.


    Find where the require is called throughout your

    application, and replace that with your new function call
    or object method.
Global variables everywhere
<?php

$account_id = $_POST['acct_id'];
$account = new Account($account_id);

function getPurchases() {
  global $account;
  global $database;
  ...
}

function   getLanguage() {
  global   $account;
  global   $database;
  global   $i18n;
  ...
}
Removing globals one by one
Common globals:
    $_POST and $_GET


    Session or cookie data


    Database handles


    User account


    Language

Do you still have
register_globals on?
    You may have heard: this is a bad idea.


    You may think that it will be impossible to fix.


    It's not. Turn on E_ALL.


    Spider your site and grep for uninitialized variables.


    It's some work, but not as hard as you think. It's worth it.

$_POST and $_GET
    These aren't horrible.


    But not horrible isn't a very high standard.


class InputVariable {
   public function __construct($name) {...}
   public function isSet() {...}
   public function isGet() {...}
   public function isPost() {...}
   public function getAsString() {...}
   public function getAsInt() {...}
   ...
}
The database global object
    Very common in PHP code


    Again, not horrible


    Prevents testing


    Prevents multiple databases

Parameterizing the DB handle
    Does it need to be everywhere?


    Can you pass it in to a function or to a constructor?


    The process is simple.


        Add database parameter.
    

        Pass in that global variable.
    

        If the call is not in global scope, find out how to pass in
    
        that variable to the current scope.
        Repeat.
    
Parameterizing globals
<?php

$account_id = $_POST['acct_id'];
$account = new Account($database, $account_id);

function getPurchases($account) {
  global $account;
  global $database;
  ...
}

function   getLanguage($account, $i18n) {
  global   $account;
  global   $database;
  global   $i18n;
  ...
}
Maybe it does have to be everywhere.
    Use a singleton.


    But not really.


    Make a way to change the singleton instance.


        Global define or environment variable.
    

        Static mutator.
    
A quick recap
What are some specific problems in legacy PHP code?
    Mixed PHP and HTML – confusion between controller

    and view
    Use of require statements instead of function calls


    Unnecessary global variables causing dependencies

Further reading
    Working Effectively With Legacy Code, Michael Feathers


    Refactoring, Martin Fowler

Questions?
crnixon@gmail.com

Slides available at:
http://clintonrnixon.net

Más contenido relacionado

La actualidad más candente

November Camp - Spec BDD with PHPSpec 2
November Camp - Spec BDD with PHPSpec 2November Camp - Spec BDD with PHPSpec 2
November Camp - Spec BDD with PHPSpec 2Kacper Gunia
 
The IoC Hydra - Dutch PHP Conference 2016
The IoC Hydra - Dutch PHP Conference 2016The IoC Hydra - Dutch PHP Conference 2016
The IoC Hydra - Dutch PHP Conference 2016Kacper Gunia
 
PhpSpec 2.0 ilustrated by examples
PhpSpec 2.0 ilustrated by examplesPhpSpec 2.0 ilustrated by examples
PhpSpec 2.0 ilustrated by examplesMarcello Duarte
 
Models and Service Layers, Hemoglobin and Hobgoblins
Models and Service Layers, Hemoglobin and HobgoblinsModels and Service Layers, Hemoglobin and Hobgoblins
Models and Service Layers, Hemoglobin and HobgoblinsRoss Tuck
 
Forget about index.php and build you applications around HTTP!
Forget about index.php and build you applications around HTTP!Forget about index.php and build you applications around HTTP!
Forget about index.php and build you applications around HTTP!Kacper Gunia
 
Command Bus To Awesome Town
Command Bus To Awesome TownCommand Bus To Awesome Town
Command Bus To Awesome TownRoss Tuck
 
購物車程式架構簡介
購物車程式架構簡介購物車程式架構簡介
購物車程式架構簡介Jace Ju
 
Introduction to Zend Framework web services
Introduction to Zend Framework web servicesIntroduction to Zend Framework web services
Introduction to Zend Framework web servicesMichelangelo van Dam
 
Advanced php testing in action
Advanced php testing in actionAdvanced php testing in action
Advanced php testing in actionJace Ju
 
Symfony World - Symfony components and design patterns
Symfony World - Symfony components and design patternsSymfony World - Symfony components and design patterns
Symfony World - Symfony components and design patternsŁukasz Chruściel
 
Database Design Patterns
Database Design PatternsDatabase Design Patterns
Database Design PatternsHugo Hamon
 
Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Leonardo Proietti
 
When cqrs meets event sourcing
When cqrs meets event sourcingWhen cqrs meets event sourcing
When cqrs meets event sourcingManel Sellés
 
Your code sucks, let's fix it
Your code sucks, let's fix itYour code sucks, let's fix it
Your code sucks, let's fix itRafael Dohms
 
Forget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers CracowForget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers CracowKacper Gunia
 
Min-Maxing Software Costs - Laracon EU 2015
Min-Maxing Software Costs - Laracon EU 2015Min-Maxing Software Costs - Laracon EU 2015
Min-Maxing Software Costs - Laracon EU 2015Konstantin Kudryashov
 
Система рендеринга в Magento
Система рендеринга в MagentoСистема рендеринга в Magento
Система рендеринга в MagentoMagecom Ukraine
 
Symfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il clienteSymfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il clienteLeonardo Proietti
 
Things I Believe Now That I'm Old
Things I Believe Now That I'm OldThings I Believe Now That I'm Old
Things I Believe Now That I'm OldRoss Tuck
 

La actualidad más candente (20)

November Camp - Spec BDD with PHPSpec 2
November Camp - Spec BDD with PHPSpec 2November Camp - Spec BDD with PHPSpec 2
November Camp - Spec BDD with PHPSpec 2
 
The IoC Hydra - Dutch PHP Conference 2016
The IoC Hydra - Dutch PHP Conference 2016The IoC Hydra - Dutch PHP Conference 2016
The IoC Hydra - Dutch PHP Conference 2016
 
PhpSpec 2.0 ilustrated by examples
PhpSpec 2.0 ilustrated by examplesPhpSpec 2.0 ilustrated by examples
PhpSpec 2.0 ilustrated by examples
 
Models and Service Layers, Hemoglobin and Hobgoblins
Models and Service Layers, Hemoglobin and HobgoblinsModels and Service Layers, Hemoglobin and Hobgoblins
Models and Service Layers, Hemoglobin and Hobgoblins
 
Forget about index.php and build you applications around HTTP!
Forget about index.php and build you applications around HTTP!Forget about index.php and build you applications around HTTP!
Forget about index.php and build you applications around HTTP!
 
Command Bus To Awesome Town
Command Bus To Awesome TownCommand Bus To Awesome Town
Command Bus To Awesome Town
 
購物車程式架構簡介
購物車程式架構簡介購物車程式架構簡介
購物車程式架構簡介
 
Introduction to Zend Framework web services
Introduction to Zend Framework web servicesIntroduction to Zend Framework web services
Introduction to Zend Framework web services
 
Advanced php testing in action
Advanced php testing in actionAdvanced php testing in action
Advanced php testing in action
 
Symfony World - Symfony components and design patterns
Symfony World - Symfony components and design patternsSymfony World - Symfony components and design patterns
Symfony World - Symfony components and design patterns
 
Database Design Patterns
Database Design PatternsDatabase Design Patterns
Database Design Patterns
 
Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5
 
When cqrs meets event sourcing
When cqrs meets event sourcingWhen cqrs meets event sourcing
When cqrs meets event sourcing
 
Your code sucks, let's fix it
Your code sucks, let's fix itYour code sucks, let's fix it
Your code sucks, let's fix it
 
Forget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers CracowForget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers Cracow
 
Min-Maxing Software Costs - Laracon EU 2015
Min-Maxing Software Costs - Laracon EU 2015Min-Maxing Software Costs - Laracon EU 2015
Min-Maxing Software Costs - Laracon EU 2015
 
Система рендеринга в Magento
Система рендеринга в MagentoСистема рендеринга в Magento
Система рендеринга в Magento
 
Symfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il clienteSymfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il cliente
 
Min-Maxing Software Costs
Min-Maxing Software CostsMin-Maxing Software Costs
Min-Maxing Software Costs
 
Things I Believe Now That I'm Old
Things I Believe Now That I'm OldThings I Believe Now That I'm Old
Things I Believe Now That I'm Old
 

Destacado

PHP 7.1 : elegance of our legacy
PHP 7.1 : elegance of our legacyPHP 7.1 : elegance of our legacy
PHP 7.1 : elegance of our legacyDamien Seguy
 
Dealing With Legacy PHP Applications
Dealing With Legacy PHP ApplicationsDealing With Legacy PHP Applications
Dealing With Legacy PHP ApplicationsViget Labs
 
Working with Legacy Code
Working with Legacy CodeWorking with Legacy Code
Working with Legacy CodeEyal Golan
 
Working Effectively With Legacy Code
Working Effectively With Legacy CodeWorking Effectively With Legacy Code
Working Effectively With Legacy Codescidept
 
Working With Legacy Code
Working With Legacy CodeWorking With Legacy Code
Working With Legacy CodeAndrea Polci
 
Transforming legacy PHP applications with Symfony2 and Varnish
Transforming legacy PHP applications with Symfony2 and VarnishTransforming legacy PHP applications with Symfony2 and Varnish
Transforming legacy PHP applications with Symfony2 and VarnishCraig Marvelley
 
Pimp legacy PHP apps with Apigility - TrueNorthPHP 2014
Pimp legacy PHP apps with Apigility - TrueNorthPHP 2014Pimp legacy PHP apps with Apigility - TrueNorthPHP 2014
Pimp legacy PHP apps with Apigility - TrueNorthPHP 2014Michelangelo van Dam
 
XP Days Ukraine 2014 - Refactoring legacy code
XP Days Ukraine 2014 - Refactoring legacy codeXP Days Ukraine 2014 - Refactoring legacy code
XP Days Ukraine 2014 - Refactoring legacy codeDmytro Mindra
 
XPDays Ukraine: Legacy
XPDays Ukraine: LegacyXPDays Ukraine: Legacy
XPDays Ukraine: LegacyVictor_Cr
 
ITGM#4 Технический долг 2.0
ITGM#4 Технический долг 2.0ITGM#4 Технический долг 2.0
ITGM#4 Технический долг 2.0Maxim Shulga
 
From Legacy to DDD in PHP | Tech Talks | Privalia
From Legacy to DDD in PHP | Tech Talks | PrivaliaFrom Legacy to DDD in PHP | Tech Talks | Privalia
From Legacy to DDD in PHP | Tech Talks | PrivaliaJordi Vila Gallardo
 
Club of anonimous developers "Refactoring: Legacy code"
Club of anonimous developers "Refactoring: Legacy code"Club of anonimous developers "Refactoring: Legacy code"
Club of anonimous developers "Refactoring: Legacy code"Victor_Cr
 
Legacy: как победить в гонке (Joker)
Legacy: как победить в гонке (Joker)Legacy: как победить в гонке (Joker)
Legacy: как победить в гонке (Joker)Victor_Cr
 
Living With Legacy Code
Living With Legacy CodeLiving With Legacy Code
Living With Legacy CodeRowan Merewood
 
Working Effectively With Legacy Code
Working Effectively With Legacy CodeWorking Effectively With Legacy Code
Working Effectively With Legacy CodeNaresh Jain
 
Refactoring 101
Refactoring 101Refactoring 101
Refactoring 101Adam Culp
 

Destacado (16)

PHP 7.1 : elegance of our legacy
PHP 7.1 : elegance of our legacyPHP 7.1 : elegance of our legacy
PHP 7.1 : elegance of our legacy
 
Dealing With Legacy PHP Applications
Dealing With Legacy PHP ApplicationsDealing With Legacy PHP Applications
Dealing With Legacy PHP Applications
 
Working with Legacy Code
Working with Legacy CodeWorking with Legacy Code
Working with Legacy Code
 
Working Effectively With Legacy Code
Working Effectively With Legacy CodeWorking Effectively With Legacy Code
Working Effectively With Legacy Code
 
Working With Legacy Code
Working With Legacy CodeWorking With Legacy Code
Working With Legacy Code
 
Transforming legacy PHP applications with Symfony2 and Varnish
Transforming legacy PHP applications with Symfony2 and VarnishTransforming legacy PHP applications with Symfony2 and Varnish
Transforming legacy PHP applications with Symfony2 and Varnish
 
Pimp legacy PHP apps with Apigility - TrueNorthPHP 2014
Pimp legacy PHP apps with Apigility - TrueNorthPHP 2014Pimp legacy PHP apps with Apigility - TrueNorthPHP 2014
Pimp legacy PHP apps with Apigility - TrueNorthPHP 2014
 
XP Days Ukraine 2014 - Refactoring legacy code
XP Days Ukraine 2014 - Refactoring legacy codeXP Days Ukraine 2014 - Refactoring legacy code
XP Days Ukraine 2014 - Refactoring legacy code
 
XPDays Ukraine: Legacy
XPDays Ukraine: LegacyXPDays Ukraine: Legacy
XPDays Ukraine: Legacy
 
ITGM#4 Технический долг 2.0
ITGM#4 Технический долг 2.0ITGM#4 Технический долг 2.0
ITGM#4 Технический долг 2.0
 
From Legacy to DDD in PHP | Tech Talks | Privalia
From Legacy to DDD in PHP | Tech Talks | PrivaliaFrom Legacy to DDD in PHP | Tech Talks | Privalia
From Legacy to DDD in PHP | Tech Talks | Privalia
 
Club of anonimous developers "Refactoring: Legacy code"
Club of anonimous developers "Refactoring: Legacy code"Club of anonimous developers "Refactoring: Legacy code"
Club of anonimous developers "Refactoring: Legacy code"
 
Legacy: как победить в гонке (Joker)
Legacy: как победить в гонке (Joker)Legacy: как победить в гонке (Joker)
Legacy: как победить в гонке (Joker)
 
Living With Legacy Code
Living With Legacy CodeLiving With Legacy Code
Living With Legacy Code
 
Working Effectively With Legacy Code
Working Effectively With Legacy CodeWorking Effectively With Legacy Code
Working Effectively With Legacy Code
 
Refactoring 101
Refactoring 101Refactoring 101
Refactoring 101
 

Similar a Dealing with Legacy PHP Applications

Quality assurance for php projects with PHPStorm
Quality assurance for php projects with PHPStormQuality assurance for php projects with PHPStorm
Quality assurance for php projects with PHPStormMichelangelo van Dam
 
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you needDutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you needKacper Gunia
 
Clear php reference
Clear php referenceClear php reference
Clear php referenceDamien Seguy
 
Becoming a better WordPress Developer
Becoming a better WordPress DeveloperBecoming a better WordPress Developer
Becoming a better WordPress DeveloperJoey Kudish
 
Using Geeklog as a Web Application Framework
Using Geeklog as a Web Application FrameworkUsing Geeklog as a Web Application Framework
Using Geeklog as a Web Application FrameworkDirk Haun
 
Web internship Yii Framework
Web internship  Yii FrameworkWeb internship  Yii Framework
Web internship Yii FrameworkNoveo
 
Ruby on Rails For Java Programmers
Ruby on Rails For Java ProgrammersRuby on Rails For Java Programmers
Ruby on Rails For Java Programmerselliando dias
 
TDC2016SP - Trilha Developing for Business
TDC2016SP - Trilha Developing for BusinessTDC2016SP - Trilha Developing for Business
TDC2016SP - Trilha Developing for Businesstdc-globalcode
 
Rapid Prototyping with PEAR
Rapid Prototyping with PEARRapid Prototyping with PEAR
Rapid Prototyping with PEARMarkus Wolff
 
Who Needs Ruby When You've Got CodeIgniter
Who Needs Ruby When You've Got CodeIgniterWho Needs Ruby When You've Got CodeIgniter
Who Needs Ruby When You've Got CodeIgniterciconf
 
Gail villanueva add muscle to your wordpress site
Gail villanueva   add muscle to your wordpress siteGail villanueva   add muscle to your wordpress site
Gail villanueva add muscle to your wordpress sitereferences
 
CodeIgniter PHP MVC Framework
CodeIgniter PHP MVC FrameworkCodeIgniter PHP MVC Framework
CodeIgniter PHP MVC FrameworkBo-Yi Wu
 
symfony on action - WebTech 207
symfony on action - WebTech 207symfony on action - WebTech 207
symfony on action - WebTech 207patter
 
Building Testable PHP Applications
Building Testable PHP ApplicationsBuilding Testable PHP Applications
Building Testable PHP Applicationschartjes
 
Meet Magento Belarus debug Pavel Novitsky (eng)
Meet Magento Belarus debug Pavel Novitsky (eng)Meet Magento Belarus debug Pavel Novitsky (eng)
Meet Magento Belarus debug Pavel Novitsky (eng)Pavel Novitsky
 
[Bristol WordPress] Supercharging WordPress Development
[Bristol WordPress] Supercharging WordPress Development[Bristol WordPress] Supercharging WordPress Development
[Bristol WordPress] Supercharging WordPress DevelopmentAdam Tomat
 

Similar a Dealing with Legacy PHP Applications (20)

Quality assurance for php projects with PHPStorm
Quality assurance for php projects with PHPStormQuality assurance for php projects with PHPStorm
Quality assurance for php projects with PHPStorm
 
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you needDutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you need
 
Yii Introduction
Yii IntroductionYii Introduction
Yii Introduction
 
Clear php reference
Clear php referenceClear php reference
Clear php reference
 
Becoming a better WordPress Developer
Becoming a better WordPress DeveloperBecoming a better WordPress Developer
Becoming a better WordPress Developer
 
Using Geeklog as a Web Application Framework
Using Geeklog as a Web Application FrameworkUsing Geeklog as a Web Application Framework
Using Geeklog as a Web Application Framework
 
Web internship Yii Framework
Web internship  Yii FrameworkWeb internship  Yii Framework
Web internship Yii Framework
 
Ruby on Rails For Java Programmers
Ruby on Rails For Java ProgrammersRuby on Rails For Java Programmers
Ruby on Rails For Java Programmers
 
Developing for Business
Developing for BusinessDeveloping for Business
Developing for Business
 
TDC2016SP - Trilha Developing for Business
TDC2016SP - Trilha Developing for BusinessTDC2016SP - Trilha Developing for Business
TDC2016SP - Trilha Developing for Business
 
Rapid Prototyping with PEAR
Rapid Prototyping with PEARRapid Prototyping with PEAR
Rapid Prototyping with PEAR
 
Who Needs Ruby When You've Got CodeIgniter
Who Needs Ruby When You've Got CodeIgniterWho Needs Ruby When You've Got CodeIgniter
Who Needs Ruby When You've Got CodeIgniter
 
Gail villanueva add muscle to your wordpress site
Gail villanueva   add muscle to your wordpress siteGail villanueva   add muscle to your wordpress site
Gail villanueva add muscle to your wordpress site
 
CodeIgniter PHP MVC Framework
CodeIgniter PHP MVC FrameworkCodeIgniter PHP MVC Framework
CodeIgniter PHP MVC Framework
 
Code Igniter 2
Code Igniter 2Code Igniter 2
Code Igniter 2
 
symfony on action - WebTech 207
symfony on action - WebTech 207symfony on action - WebTech 207
symfony on action - WebTech 207
 
Building Testable PHP Applications
Building Testable PHP ApplicationsBuilding Testable PHP Applications
Building Testable PHP Applications
 
Meet Magento Belarus debug Pavel Novitsky (eng)
Meet Magento Belarus debug Pavel Novitsky (eng)Meet Magento Belarus debug Pavel Novitsky (eng)
Meet Magento Belarus debug Pavel Novitsky (eng)
 
[Bristol WordPress] Supercharging WordPress Development
[Bristol WordPress] Supercharging WordPress Development[Bristol WordPress] Supercharging WordPress Development
[Bristol WordPress] Supercharging WordPress Development
 
PHPSpec BDD Framework
PHPSpec BDD FrameworkPHPSpec BDD Framework
PHPSpec BDD Framework
 

Más de Clinton Dreisbach

Más de Clinton Dreisbach (7)

Migrating Legacy Rails Apps to Rails 3
Migrating Legacy Rails Apps to Rails 3Migrating Legacy Rails Apps to Rails 3
Migrating Legacy Rails Apps to Rails 3
 
Having Fun with Play
Having Fun with PlayHaving Fun with Play
Having Fun with Play
 
Narwhal and the Adventures of CommonJS
Narwhal and the Adventures of CommonJSNarwhal and the Adventures of CommonJS
Narwhal and the Adventures of CommonJS
 
HTML5 Now
HTML5 NowHTML5 Now
HTML5 Now
 
Unearthed Arcana for Web People
Unearthed Arcana for Web PeopleUnearthed Arcana for Web People
Unearthed Arcana for Web People
 
The Joy Of Ruby
The Joy Of RubyThe Joy Of Ruby
The Joy Of Ruby
 
Advanced Internationalization with Rails
Advanced Internationalization with RailsAdvanced Internationalization with Rails
Advanced Internationalization with Rails
 

Último

Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CVKhem
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Enterprise Knowledge
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?Antenna Manufacturer Coco
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessPixlogix Infotech
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024Results
 

Último (20)

Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your Business
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 

Dealing with Legacy PHP Applications

  • 2. What is a legacy application? Code you didn't write  Code you wouldn't write  Untested code  Code with competing visions 
  • 3. What do we do with legacy code? We refactor! Refactoring is safely changing the implementation of code without changing the behavior of code.
  • 4. Bad code smells What are some specific problems in legacy PHP code? No separation between PHP and HTML  Lots of requires, few method calls  Global variables 
  • 5. No separation between PHP and HTML <h1>Orders</h1> <?php $account = new Account($account_id); $account->loadOrders(); foreach ($account->getOrders() as $order) { echo '<h2>' . $order['id'] . '</h2>'; echo '<p>Status: ' . lookup_status($order['status_id']) . '<br />; echo 'Total: '; $total = array_reduce($order['purchases'], create_function('$a, $b', '$a += $b; return $a')); echo $total . '</p>'; } ?>
  • 6. Separating controllers and views Even without a solid MVC architecture, this helps  You can do this in several safe and easy steps  You absolutely will find pain points 
  • 7. Why do I need to do this? Your code complexity will increase  echo isn't as fun as it looks  You will find hidden bugs and mistakes 
  • 8. The simplest view class class View { protected static $VIEW_PATH = '/wherever/views/'; public function assign($name, $value) { return $this->$name = $value; } public function render($filename) { $filename = self::$VIEW_PATH . $filename; if (is_file($filename)) { ob_start(); include($filename); return ob_get_clean(); } } }
  • 9. Obvious improvements to make Error handling  Assignment by reference  Changing view path  Display convenience method  Use-specific subclasses with helper methods 
  • 10. The separation process Gather all your code  Sift and separate controller from view code  Assign variables to the view object  Change all variable references in the view code  Split the files  Find duplicated views 
  • 11. The rules of view code Allowed: Control structures  echo, or <?= $var ?>  Display-specific functions, never nested  Not allowed: Assignment  Other function calls 
  • 12. Gather and sift code The step you won't like: gather all code for this controller  Wipe brow  Draw a line at the top of the code  Move controller code above this line, fixing as necessary  At this point, everything is view code 
  • 13. Code gathered <?php // View code goes below here ?> <h1>Orders</h1> <?php $account = new Account($account_id); $account->loadOrders(); foreach ($account->getOrders() as $order) { echo '<h2>' . $order['id'] . '</h2>'; echo '<p>Status: ' . lookup_status($order['status_id']) . '<br />; echo 'Total: '; $total = array_reduce($order['purchases'], create_function('$a, $b', '$a += $b; return $a')); echo $total . '</p>'; } ?>
  • 14. Some controller code moved <?php $account = new Account($account_id); $account->loadOrders(); ?> <?php // View code goes below here ?> <h1>Orders</h1> <?php foreach ($account->getOrders() as $order) { ?> <h2><?= $order['id'] ?></h2> <p>Status: <?= lookup_status($order['status_id']) <br /> Total: <?= array_reduce($order['purchases'], create_function('$a, $b', '$a += $b; return $a')) ?> </p> <?php } ?>
  • 15. Alternative control structures <?php if ($foo): ?> ... <?php endif; ?> <?php foreach ($this as $that): ?> ... <?php endforeach; ?>
  • 16. Using alternative control structures <?php $account = new Account($account_id); $account->loadOrders(); ?> <?php // View code goes below here ?> <h1>Orders</h1> <?php foreach ($account->getOrders() as $order): ?> <h2><?= $order['id'] ?></h2> <p>Status: <?= lookup_status($order['status_id']) ?> <br /> Total: <?= array_reduce($order['purchases'], create_function('$a, $b', '$a += $b; return $a')) ?> </p> <?php endforeach; ?>
  • 17. A frustrating problem <?php foreach ($account->getOrders() as $order): ?> <h2><?= $order['id'] ?></h2> <p>Status: <?= lookup_status($order['status_id']) ?> <br /> Total: <?= array_reduce($order['purchases'], create_function('$a, $b', '$a += $b; return $a')) ?> </p> <?php endforeach; ?>
  • 18. Dealing with this problem There are two approaches. You can create a new array of variables for your view.  Or, you can encapsulate this logic in an object. 
  • 19. Our new order object <?php class Order { ... public function getStatus() { return lookup_status($this->getStatusId()); } public function getTotal() { return array_reduce($this->getPurchases(), create_function('$a, $b', '$a += $b; return $a')); } } ?>
  • 20. Logic removed from view code <?php $account = new Account($account_id); $account->loadOrders(); $orders = $account->getOrders(); ?> <?php // View code goes below here ?> <h1>Orders</h1> <?php foreach ($orders as $order): ?> <h2><?= $order->getId() ?></h2> <p>Status: <?= $order->getStatus() ?> <br /> Total: <?= $order->getTotal() ?> </p> <?php endforeach; ?>
  • 21. Change all variables to view object variables Assign variables to the view object.  $view->assign('foo', $foo); One-by-one, change variables in view code.  Test to convince yourself.  You will probably iterate back to the previous step.  Document inputs to the view. 
  • 22. View object created <?php $account = new Account($account_id); $account->loadOrders(); $orders = $account->getOrders(); $view = new View(); $view->assign('orders', $orders); ?> <?php // View code goes below here ?> <h1>Orders</h1> <?php foreach ($view->orders as $order): ?> <h2><?= $order->getId() ?></h2> <p>Status: <?= $order->getStatus() ?> <br /> Total: <?= $order->getTotal() ?> </p> <?php endforeach; ?>
  • 23. Separate the files Create a new file for the view code.  Important! Search and replace $view with $this.  Test one more time. 
  • 24. Our two files <?php $account = new Account($account_id); $account->loadOrders(); $orders = $account->getOrders(); $view = new View(); $view->assign('orders', $orders); $view->display('orders.tpl'); ?> <h1>Orders</h1> <?php foreach ($this->orders as $order): ?> <h2><?= $order->getId() ?></h2> <p>Status: <?= $order->getStatus() ?> <br /> Total: <?= $order->getTotal() ?> </p> <?php endforeach; ?>
  • 25. Find duplicated views As you do this to multiple controllers, you will see  repetition. There will probably be subtle differences.  Take the time to re-work these so you can re-use view  files. Note! You can include views in other views with  $this->render('included_file.tpl');
  • 26. Using nested requires instead of function calls <?php require_once('db_setup_inc.php'); require_once('account_auth_inc.php'); require_once('i18n_inc.php'); echo '<h1>Orders for account #' . $account_id . '</h1>'; require('get_all_orders_inc.php'); ...
  • 27. Untangling a require web Require statements which call other require statements.  Can be very complex.  Dependent on application structure. 
  • 28. Important reasons to untangle this web Remove unneeded complexity.  Create less procedural code.  Prior to PHP 5.2, require_once and include_once  are more expensive than you would think. If you are requiring class definitions, and you have a  standard file naming method, use __autoload().
  • 29. The untangling process Identify inputs  Identify outputs  Wrap the file in a method  Refactor method  Move method to correct location 
  • 30. Identify inputs and outputs Find all variables expected to be set before this file is  included. One possible way: execute this file by itself.  Find all variables expected to be set or mutated by this  file. Set variables are easy: comment out the require and  watch the errors. Mutated is the set of inputs changed. Learn to search for  these!
  • 31. account_auth_inc.php <?php $auth_token = $_COOKIE['token']; if ($auth_token) { $acct_id = $db->GetOne('SELECT acct_id FROM logins WHERE auth_token = ?', array($auth_token)); } if ($acct_id) { $acct = new Account($acct_id); } else { $acct = null; } $_COOKIE['token'] = gen_new_token($auth_token);
  • 32. Wrap the file in a function Wrap the entire include in a function.  Pass all input variables.  Return all output variables as an array.  And then, call that function at the bottom of the required  file! This is a mess! 
  • 33. Function-wrapped <?php function account_auth($db, $auth_token) { if ($auth_token) { $acct_id = $db->GetOne('SELECT acct_id FROM logins WHERE auth_token = ?', array($auth_token)); } if ($acct_id) { $acct = new Account($acct_id); } else { $acct = null; } return array($acct, gen_new_token($auth_token)); } list($acct, $_COOKIE['token']) = account_auth($db, $_COOKIE['token']);
  • 34. Refactor until complete Tease out the functions, or objects, inside this function.  If you are returning a lot of data, see if it can be an  object. Leave your temporary big function in place, so that your  outside code doesn't break. Keep updating it to deal with your refactoring.
  • 35. Moved token handling to Account <?php function account_auth($db, $auth_token) { // Instead of null, we now return an unloaded Account. $acct = new Account(); if ($auth_token) { // SQL code from before $acct->loadFromToken($auth_token); // Token generation and cookie setting $acct->genNewToken($auth_token); } return $acct; } $acct = account_auth($db, $_COOKIE['token']);
  • 36. Move to correct location Finally!  Figure out where these functions or objects should live in  your application. Move them there.  Find where the require is called throughout your  application, and replace that with your new function call or object method.
  • 37. Global variables everywhere <?php $account_id = $_POST['acct_id']; $account = new Account($account_id); function getPurchases() { global $account; global $database; ... } function getLanguage() { global $account; global $database; global $i18n; ... }
  • 38. Removing globals one by one Common globals: $_POST and $_GET  Session or cookie data  Database handles  User account  Language 
  • 39. Do you still have register_globals on? You may have heard: this is a bad idea.  You may think that it will be impossible to fix.  It's not. Turn on E_ALL.  Spider your site and grep for uninitialized variables.  It's some work, but not as hard as you think. It's worth it. 
  • 40. $_POST and $_GET These aren't horrible.  But not horrible isn't a very high standard.  class InputVariable { public function __construct($name) {...} public function isSet() {...} public function isGet() {...} public function isPost() {...} public function getAsString() {...} public function getAsInt() {...} ... }
  • 41. The database global object Very common in PHP code  Again, not horrible  Prevents testing  Prevents multiple databases 
  • 42. Parameterizing the DB handle Does it need to be everywhere?  Can you pass it in to a function or to a constructor?  The process is simple.  Add database parameter.  Pass in that global variable.  If the call is not in global scope, find out how to pass in  that variable to the current scope. Repeat. 
  • 43. Parameterizing globals <?php $account_id = $_POST['acct_id']; $account = new Account($database, $account_id); function getPurchases($account) { global $account; global $database; ... } function getLanguage($account, $i18n) { global $account; global $database; global $i18n; ... }
  • 44. Maybe it does have to be everywhere. Use a singleton.  But not really.  Make a way to change the singleton instance.  Global define or environment variable.  Static mutator. 
  • 45. A quick recap What are some specific problems in legacy PHP code? Mixed PHP and HTML – confusion between controller  and view Use of require statements instead of function calls  Unnecessary global variables causing dependencies 
  • 46. Further reading Working Effectively With Legacy Code, Michael Feathers  Refactoring, Martin Fowler 