O'Reilly logo

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Modernizing Legacy Applications in PHP

Book Description

Get your code under control in a series of small, specific steps

About This Book

  • Learn to extract and replace legacy artifacts,
  • Improve your application from the ground up while keeping your codebase fully operational,
  • Improve the quality of your legacy applications.

Who This Book Is For

PHP developers from all skill levels will be able to get value from this book and will be able to transform their spaghetti code applications to clean, modular applications. If you are in the midst of a legacy refactor or you find yourself in a state of despair caused by the code you have inherited, this is the book for you. All you need is to have PHP 5.0 installed, and you’re all set to change the way you maintain and deploy your code!

What You Will Learn

  • Replace global and new with dependency injection
  • Extract SQL statements to gateways
  • Convert action logic to controllers
  • Remove repeated logic in page scripts
  • Create maintainable PHP code from crufty legacy PHP

In Detail

Have you noticed that your legacy PHP application is composed of page scripts placed directly in the document root of the web server? Or, do your page scripts, along with any other classes and functions, combine the concerns of model, view, and controller into the same scope? Is the majority of the logical flow incorporated as include files and global functions rather than class methods? Working with such a legacy application feels like dragging your feet through mud, doesn’t it?This book will show you how to modernize your application in terms of practice and technique, rather than in terms of using tools like frameworks and libraries, by extracting and replacing its legacy artifacts. We will use a step-by-step approach, moving slowly and methodically, to improve your application from the ground up. We’ll show you how dependency injection can replace both the new and global dependencies. We’ll also show you how to change the presentation logic to view files and the action logic to a controller. Moreover, we’ll keep your application running the whole time. Each completed step in the process will keep your codebase fully operational with higher quality. When we are done, you will be able to breeze through your code like the wind. Your code will be autoloaded, dependency-injected, unit-tested, layer-separated, and front-controlled. Most of the very limited code we will add to your application is specific to this book. We will be improving ourselves as programmers, as well as improving the quality of our legacy application.

Style and approach

This book gives developers an easy-to-follow, practical and powerful process to bring their applications up to a modern baseline. Each step in the book is practical, self-contained and moves you closer to the end goal you seek: maintainable code. As you follow the exercises in the book, the author almost anticipates your questions and you will have the answers, ready to be implemented on your project.

Downloading the example code for this book. You can download the example code files for all Packt books you have purchased from your account at http://www.PacktPub.com. If you purchased this book elsewhere, you can visit http://www.PacktPub.com/support and register to have the code file.

Table of Contents

  1. Modernizing Legacy Applications in PHP
    1. Table of Contents
    2. Modernizing Legacy Applications in PHP
    3. Credits
    4. Foreword
    5. About the Author
    6. Acknowledgement
    7. www.PacktPub.com
      1. eBooks, discount offers, and more
        1. Why subscribe?
    8. Preface
    9. 1. Legacy Applications
      1. The typical PHP application
        1. File Structure
        2. Page Scripts
        3. Rewrite or Refactor?
        4. The Pros and Cons of Rewriting
        5. Why Don't Rewrites Work?
          1. The Context-switching problem
          2. The Knowledge problem
          3. The Schedule Problem
          4. Iterative Refactoring
      2. Legacy Frameworks
        1. Framework-based Legacy Applications
        2. Refactoring to a Framework
      3. Review and next steps
    10. 2. Prerequisites
      1. Revision control
        1. PHP version
        2. Editor/IDE
        3. Style Guide
      2. Test suite
      3. Review and next steps
    11. 3. Implement an Autoloader
      1. PSR-0
      2. A Single Location for Classes
        1. Add Autoloader Code
        2. As a Global Function
          1. As a Closure
          2. As a Static or Instance method
      3. Using The __autoload() Function
        1. Autoloader Priority
      4. Common Questions
        1. What If I Already Have An Autoloader?
        2. What are the Performance Implications Of Autoloading?
        3. How Do Class Names Map To File Names?
      5. Review and next steps
    12. 4. Consolidate Classes and Functions
      1. Consolidate Class Files
        1. Find a candidate include
        2. Move the class file
        3. Remove the related include calls
        4. Spot check the codebase
        5. Commit, Push, Notify QA
        6. Do ... While
      2. Consolidate functions into class files
        1. Find a candidate include
        2. Convert the function file to a class file
          1. Change function calls to static method calls
          2. Spot check the static method calls
          3. Move the class file
        3. Do ... While
      3. Common Questions
        1. Should we remove the autoloader include call?
        2. How should we pick files for candidate include calls?
        3. What if an include defines more than one class?
        4. What if the one-class-per-file rule is disagreeable?
        5. What if a Class or Function is defined inline?
        6. What if a definition file also executes logic?
          1. What if two classes have the same name?
        7. What about third-party libraries?
          1. What about system-wide libraries?
        8. For functions, can we use instance methods instead of static methods?
          1. Can we automate this process?
      4. Review and next steps
    13. 5. Replace global With Dependency Injection
      1. Global Dependencies
        1. The replacement process
        2. Find a global variable
        3. Convert global variables to properties
        4. Spot check the class
        5. Convert global properties to constructor parameters
          1. Convert instantiations to use parameters
        6. Spot check, Commit, Push, Notify QA
        7. Do ... While
      2. Common Questions
        1. What if we find a global in a static method?
        2. Is there an alternative conversion process?
        3. What about class names in variables?
        4. What about superglobals?
        5. What about $GLOBALS?
      3. Review and next steps
    14. 6. Replace new with Dependency Injection
      1. Embedded instantiation
      2. The replacement process
        1. Find a new keyword
        2. Extract One-Time creation to dependency injection
        3. Extract repeated creation to factory
      3. Change instantiation calls
        1. Spot Check, Commit, Push, Notify QA
        2. Do ... While
        3. Common Questions
          1. What About Exceptions and SPL Classes?
          2. What about Intermediary Dependencies?
          3. Isn't this a lot of code?
          4. Should a factory create collections?
        4. Can we automate all these Injections?
      4. Review and next steps
    15. 7. Write Tests
      1. Fighting test resistance
      2. The way of Testivus
        1. Setting up a test suite
          1. Install PHPUnit
          2. Create a tests/ directory
          3. Pick a class to test
          4. Write a test case
          5. Do ... While
        2. Common Questions
          1. Can we skip this step and do it later?
          2. Come On, Really, Can We Do This Later?
          3. What about hard-to-test classes?
          4. What about our earlier characterization tests?
          5. Should we test private and protected methods?
          6. Can we change a test after we write it?
          7. Do we need to test Third-party libraries?
          8. What about code coverage?
      3. Review and next steps
    16. 8. Extract SQL statements to Gateways
      1. Embedded SQL Statements
        1. The extraction process
        2. Search for SQL statements
          1. Move SQL to a Gateway class
          2. Namespace and Class names
          3. Method names
        3. An initial Gateway class method
          1. Defeating SQL Injection
          2. Write a test
          3. Replace the original code
          4. Test, Commit, Push, Notify QA
          5. Do ... While
        4. Common Questions
          1. What about INSERT, UPDATE, and DELETE Statements?
          2. What about Repetitive SQL strings?
          3. What about complex query strings?
          4. What about queries inside non-Gateway classes?
          5. Can we extend from a base Gateway class?
          6. What about multiple queries and complex result structures?
          7. What if there is no Database Class?
      2. Review and next steps
    17. 9. Extract Domain Logic to Transactions
      1. Embedded Domain Logic
        1. Domain logic patterns
      2. The Extraction Process
        1. Search for uses of Gateway
          1. Discover and Extract Relevant Domain Logic
          2. Example Extraction
          3. Spot check the remaining original code
          4. Write tests for the extracted transactions
          5. Spot check again, Commit, Push, Notify QA
          6. Do ... While
        2. Common Questions
          1. Are we talking about SQL transactions?
          2. What about repeated Domain Logic?
          3. Are printing and echoing part of Domain Logic?
          4. Can a transaction be a class instead of a Method?
          5. What about Domain Logic in Gateway classes?
          6. What about Domain logic embedded in Non-Domain classes?
      3. Review and next steps
    18. 10. Extract Presentation Logic to View Files
      1. Embedded presentation logic
        1. The Extraction process
          1. Search for Embedded presentation logic
          2. Rearrange the Page script and Spot Check
        2. Extract Presentation to View file and Spot Check
          1. Create a views/ Directory
            1. Pick a View File name
            2. Move Presentation Block to View file
          2. Add Proper Escaping
        3. Write View File Tests
          1. The tests/views/ directory
            1. Writing a View File Test
            2. Asserting Correctness Of Content
          2. Commit, Push, Notify QA
          3. Do ... While
        4. Common Questions
          1. What about Headers and Cookies?
        5. What if we already have a Template system?
          1. What about Streaming Content?
        6. What if we have lots of Presentation variables?
          1. What about class methods that generate output?
        7. What about Business Logic Mixed into the presentation?
          1. What if a page contains only presentation logic?
      2. Review and next steps
    19. 11. Extract Action Logic to Controllers
      1. Embedded action logic
        1. The Extraction Process
        2. Search for Embedded Action Logic
        3. Rearrange the Page Script and Spot Check
          1. Identify Code Blocks
          2. Move Code to Its Related Block
          3. Spot Check the Rearranged Code
          4. Extract a Controller Class
          5. Pick a Class Name
          6. Create a Skeleton Class File
        4. Move the Action Logic and Spot Check
        5. Convert Controller to Dependency Injection and Spot Check
          1. Write a Controller Test
          2. Commit, Push, Notify QA
          3. Do ... While
        6. Common Questions
          1. Can we pass parameters to the Controller method?
        7. Can a Controller have Multiple actions?
        8. What If the Controller contains include Calls?
      2. Review and next steps
    20. 12. Replace Includes in Classes
      1. Embedded include Calls
      2. The Replacement process
        1. Search for include Calls
        2. Replacing a Single include Call
        3. Replacing Multiple include Calls
        4. Copy include file to Class Method
        5. Replace the original include Call
        6. Discover coupled variables through testing
        7. Replace other include Calls and Test
        8. Delete the include file and test
          1. Write a test and refactor
          2. Convert to Dependency Injection and test
          3. Commit, Push, Notify QA
          4. Do ... While
        9. Common QuestionsCan one class receive logic from many include files?
        10. What about include calls originating in non-class files?
      3. Review and next steps
    21. 13. Separate Public and Non-Public Resources
      1. Intermingled resources
      2. The separation process
        1. Coordinate with operations personnel
        2. Create a document root directory
        3. Reconfigure the server
        4. Move public resources
        5. Commit, push, coordinate
      3. Common Questions
        1. Is This Really Necessary?
      4. Review and next steps
    22. 14. Decouple URL Paths from File Paths
      1. Coupled Paths
        1. The Decoupling Process
        2. Coordinate with Operations
          1. Add a Front Controller
          2. Create a pages/ Directory
        3. Reconfigure the Server
          1. Spot check
          2. Move Page scripts
          3. Commit, Push, Coordinate
        4. Common Questions
          1. Did we really Decouple the Paths?
      2. Review and next steps
    23. 15. Remove Repeated Logic in Page Scripts
      1. Repeated logic
        1. The Removal Process
        2. Modify the Front controller
        3. Remove Logic from Page Scripts
        4. Spot Check, Commit, Push, Notify QA
        5. Common Questions
          1. What if the Setup Work Is Inconsistent?
          2. What if we used inconsistent naming?
      2. Review and next steps
    24. 16. Add a Dependency Injection Container
      1. What is a Dependency Injection Container?
        1. Adding a DI Container
        2. Add a DI Container Include File
          1. Add a Router Service
          2. Modify the Front Controller
          3. Extract Page Scripts to Services
            1. Create a Container Service
            2. Route the URL Path to the Container Service
            3. Spot Check and Commit
          4. Do ... While
          5. Remove pages/, Commit, Push, Notify QA
        3. Common Questions
          1. How can we refine our service definitions?
          2. What if there are includes In the Page Script?
          3. Can we reduce the size of the services.php file?
          4. Can we reduce the size of the router service?
          5. What if we cannot update to PHP 5.3?
      2. Review and next steps
    25. 17. Conclusion
      1. Opportunities for improvement
      2. Conversion to Framework
      3. Review and next steps
    26. A. Typical Legacy Page Script
    27. B. Code before Gateways
    28. C. Code after Gateways
    29. D. Code after Transaction Scripts
    30. E. Code before Collecting Presentation Logic
    31. F. Code after Collecting Presentation Logic
    32. G. Code after Response View File
    33. H. Code after Controller Rearrangement
    34. I. Code after Controller Extraction
    35. J. Code after Controller Dependency Injection
    36. Index