You are previewing Pro PHP Refactoring.
O'Reilly logo
Pro PHP Refactoring

Book Description

Many businesses and organizations depend on older high-value PHP software that risks abandonment because it is impossible to maintain. The reasons for this may be that the software is not well designed; there is only one developer (the one who created the system) who can develop it because he didn't use common design patterns and documentation; or the code is procedural, not object oriented. With this book, you'll learn to identify problem code and refactor it to create more effective applications using test-driven design.

Table of Contents

  1. Copyright
  2. About the Authors
  3. About the Technical Reviewer
  4. Acknowledgments
  5. Introduction
  6. 1. Introduction
    1. 1.1. Lesson Learned
      1. 1.1.1. Hidden Gems
      2. 1.1.2. You Don't Know What You've Got 'til It's Gone
    2. 1.2. Call of Duty
  7. 2. Finding "Bad Smells" in Code
    1. 2.1. Why Code Can Smell
      1. 2.1.1. Duplicated Code
      2. 2.1.2. Long Method
      3. 2.1.3. Large Class
      4. 2.1.4. Long Parameter List
      5. 2.1.5. Divergent Change
      6. 2.1.6. Shotgun Surgery
      7. 2.1.7. Feature Envy
      8. 2.1.8. Data Clamps
      9. 2.1.9. Primitive Obsession
      10. 2.1.10. Switch Statements
      11. 2.1.11. Lazy Class
      12. 2.1.12. Speculative Generality
      13. 2.1.13. Temporary Field
      14. 2.1.14. Data Class
      15. 2.1.15. Comments
      16. 2.1.16. Procedural Code
  8. 3. Introduction to Refactoring
    1. 3.1. The Concept: What Refactoring Is
    2. 3.2. The Reason: What's the Goal of Refactoring?
      1. 3.2.1. Architecture and Structure, They Fade Away
      2. 3.2.2. Reworking Chaos into Well-Designed Code
    3. 3.3. An Example, at Last
      1. 3.3.1. Look Ma'! No Comments!
    4. 3.4. Once Is Better than Twice
    5. 3.5. Goliath Died in the End
  9. 4. Principles and Rules
    1. 4.1. Why Should You Do Refactoring?
      1. 4.1.1. Refactoring Improves the Design of Our Software
      2. 4.1.2. Refactoring Makes Software Easier to Understand
        1. 4.1.2.1. Keep It Simple and Stupid (KISS)
        2. 4.1.2.2. Don't Repeat Yourself
        3. 4.1.2.3. Test-Driven Development (TDD)
      3. 4.1.3. Refactoring Helps You Find Bugs
      4. 4.1.4. Refactoring Increases Our Productivity
    2. 4.2. When Should We Do Refactoring?
      1. 4.2.1. The Rule of Three
      2. 4.2.2. Refactoring When You Add Functionality
      3. 4.2.3. Refactoring When You Need to Fix a Bug
    3. 4.3. When You Shouldn't Do Refactoring
    4. 4.4. Some Simple Rules
      1. 4.4.1. Test Before Refactoring
      2. 4.4.2. Small and Simple Changes
      3. 4.4.3. Never Change Functionality
      4. 4.4.4. Follow the Bad Smells
      5. 4.4.5. Follow Refactoring Techniques Step-by-Step
    5. 4.5. Summary
  10. 5. Test-First Development
    1. 5.1. Building Value One-Way
    2. 5.2. Chaos in a Cage
      1. 5.2.1. Unit Tests
      2. 5.2.2. Functional Tests
    3. 5.3. You Don't Know What You've Got 'til It's Gone
      1. 5.3.1. Trust Me: Communication
      2. 5.3.2. Listen to What You Say, and Write It Down
      3. 5.3.3. Pleasant Constraints
      4. 5.3.4. Create Trust
      5. 5.3.5. Test-Driven Development
    4. 5.4. Summary
  11. 6. Refactoring Tools
    1. 6.1. PHP IDE
      1. 6.1.1. Refactoring Activities
        1. 6.1.1.1. Rename
        2. 6.1.1.2. Move
        3. 6.1.1.3. Encapsulate Field
        4. 6.1.1.4. Override
        5. 6.1.1.5. Safely Remove
      2. 6.1.2. Cross-Platform Open-Source IDE
    2. 6.2. Unit Tests with PHPUnit
      1. 6.2.1. What Is It?
      2. 6.2.2. Installation
        1. 6.2.2.1. PEAR Installation
        2. 6.2.2.2. Manual Installation
      3. 6.2.3. How to Write Unit Tests
      4. 6.2.4. How to Run Tests
      5. 6.2.5. How to Organize Our Tests
      6. 6.2.6. Test Doubles
        1. 6.2.6.1. Stub Object
        2. 6.2.6.2. Mock Object
      7. 6.2.7. PHPUnit Conclusion
    3. 6.3. Functional Test with Selenium
      1. 6.3.1. What Is It?
        1. 6.3.1.1. Selenium IDE
        2. 6.3.1.2. Selenium RC
        3. 6.3.1.3. Selenium Grid
      2. 6.3.2. Installation
      3. 6.3.3. How to Record and Run Functional Tests
      4. 6.3.4. How to Organize Selenium Tests
      5. 6.3.5. Automated Test Execution with Selenium RC
      6. 6.3.6. Selenium Conclusion
    4. 6.4. The Best of Two Worlds
      1. 6.4.1. Selenium RC and PHPUnit
      2. 6.4.2. Selenium Functional Test with PHPUnit
    5. 6.5. Summary
  12. 7. Structuring Behavior
    1. 7.1. Extract Method
      1. 7.1.1. Motivation
      2. 7.1.2. Mechanics
      3. 7.1.3. Example: No Local Variables
      4. 7.1.4. Example: Using Local Variables
      5. 7.1.5. Example: Reassigning a Local Variable
    2. 7.2. Inline Method
      1. 7.2.1. Motivation
      2. 7.2.2. Mechanics
      3. 7.2.3. Example
    3. 7.3. Inline Temp
      1. 7.3.1. Motivation
      2. 7.3.2. Mechanics
      3. 7.3.3. Example
    4. 7.4. Replace Temp with Query
      1. 7.4.1. Motivation
      2. 7.4.2. Mechanics
      3. 7.4.3. Example
    5. 7.5. Introduce Explaining Variable
      1. 7.5.1. Motivation
      2. 7.5.2. Mechanics
      3. 7.5.3. Example
    6. 7.6. Split Temporary Variable
      1. 7.6.1. Motivation
      2. 7.6.2. Mechanics
      3. 7.6.3. Example
    7. 7.7. Replace Method with Method Object
      1. 7.7.1. Motivation
      2. 7.7.2. Mechanics
      3. 7.7.3. Example
    8. 7.8. Substitute Algorithm
      1. 7.8.1. Motivation
      2. 7.8.2. Mechanics
      3. 7.8.3. Example
    9. 7.9. Summary
  13. 8. Changing Class Responsibilities
    1. 8.1. Move Method
      1. 8.1.1. Motivation
      2. 8.1.2. Mechanics
      3. 8.1.3. Example
    2. 8.2. Move Property (or Field)
      1. 8.2.1. Motivation
      2. 8.2.2. Mechanics
      3. 8.2.3. Example
    3. 8.3. Extract Class
      1. 8.3.1. Motivation
      2. 8.3.2. Mechanics
      3. 8.3.3. Example
    4. 8.4. Inline Class
      1. 8.4.1. Motivation
      2. 8.4.2. Mechanics
      3. 8.4.3. Example
    5. 8.5. Hide Delegate
      1. 8.5.1. Motivation
      2. 8.5.2. Mechanics
      3. 8.5.3. Example
    6. 8.6. Remove the Middle Man
      1. 8.6.1. Motivation
      2. 8.6.2. Mechanism
      3. 8.6.3. Example
    7. 8.7. Introduce Foreign Method
      1. 8.7.1. Motivation
      2. 8.7.2. Mechanism
      3. 8.7.3. Example
    8. 8.8. Summary
  14. 9. Dealing with Data Rationalization
    1. 9.1. Self-Encapsulate Field
      1. 9.1.1. Motivation
      2. 9.1.2. Mechanics
      3. 9.1.3. Example
    2. 9.2. Replace Data Value with Object
      1. 9.2.1. Motivation
      2. 9.2.2. Mechanics
      3. 9.2.3. Example
    3. 9.3. Change Value to Reference
      1. 9.3.1. Motivation
      2. 9.3.2. Mechanics
      3. 9.3.3. Example
    4. 9.4. Change Reference to Value
      1. 9.4.1. Motivation
      2. 9.4.2. Mechanics
    5. 9.5. Replace Array with Object
      1. 9.5.1. Motivation
      2. 9.5.2. Mechanics
      3. 9.5.3. Example
    6. 9.6. Change Unidirectional Association to Bidirectional
      1. 9.6.1. Motivation
      2. 9.6.2. Mechanics
      3. 9.6.3. Example
    7. 9.7. Change Bidirectional Association to Unidirectional
      1. 9.7.1. Motivation
      2. 9.7.2. Mechanics
      3. 9.7.3. Example
    8. 9.8. Replace Magic Number with Symbolic Constant
      1. 9.8.1. Motivation
      2. 9.8.2. Mechanics
      3. 9.8.3. Example
    9. 9.9. Encapsulate Field
      1. 9.9.1. Motivation
      2. 9.9.2. Mechanics
      3. 9.9.3. Example
    10. 9.10. Replacing Type Code with Subclasses
      1. 9.10.1. Motivation
      2. 9.10.2. Mechanics
      3. 9.10.3. Example
    11. 9.11. Replace Type Code with State/Strategy
      1. 9.11.1. Motivation
      2. 9.11.2. Mechanics
      3. 9.11.3. Example
    12. 9.12. Replace Subclass with Fields
      1. 9.12.1. Motivation
      2. 9.12.2. Mechanics
      3. 9.12.3. Example
    13. 9.13. Summary
  15. 10. Reducing to Essential Conditional Executions
    1. 10.1. Decompose Conditional
      1. 10.1.1. Motivation
      2. 10.1.2. Mechanics
      3. 10.1.3. Example
    2. 10.2. Consolidate Conditional Expression
      1. 10.2.1. Motivation
      2. 10.2.2. Mechanism
      3. 10.2.3. Example to Consolidate with ORs
      4. 10.2.4. Example to Consolidate with AND
    3. 10.3. Consolidate Duplicate Conditional Fragments
      1. 10.3.1. Motivation
      2. 10.3.2. Mechanism
      3. 10.3.3. Example
    4. 10.4. Remove Control Flag
      1. 10.4.1. Motivation
      2. 10.4.2. Mechanism
      3. 10.4.3. Example with Control Flag Replaced with Break
      4. 10.4.4. Example Replacing Control Flag with a Return Exit Point
    5. 10.5. Replace Nested Conditional with Guard Clauses
      1. 10.5.1. Motivation
      2. 10.5.2. Mechanism
      3. 10.5.3. Example
    6. 10.6. Replace Conditional with Polymorphism
      1. 10.6.1. Motivation
      2. 10.6.2. Mechanism
      3. 10.6.3. Example
    7. 10.7. Summary
  16. 11. Simplifying Method Calls
    1. 11.1. Rename Method
      1. 11.1.1. Motivation
      2. 11.1.2. Mechanics
      3. 11.1.3. Example
    2. 11.2. Add Parameter
      1. 11.2.1. Motivation
      2. 11.2.2. Mechanics
      3. 11.2.3. Example
      4. 11.2.4. Remove Parameter
      5. 11.2.5. Motivation
      6. 11.2.6. Mechanics
    3. 11.3. Separate Query from Modifier
      1. 11.3.1. Motivation
      2. 11.3.2. Mechanics
      3. 11.3.3. Example
    4. 11.4. Parameterize Method
      1. 11.4.1. Motivation
      2. 11.4.2. Mechanics
      3. 11.4.3. Example
    5. 11.5. Replace Parameter with Explicit Method
      1. 11.5.1. Motivation
      2. 11.5.2. Mechanics
      3. 11.5.3. Example
    6. 11.6. Preserve Whole Object
      1. 11.6.1. Motivation
      2. 11.6.2. Mechanics
      3. 11.6.3. Example
    7. 11.7. Replace Parameter with Method
      1. 11.7.1. Motivation
      2. 11.7.2. Mechanics
      3. 11.7.3. Example
    8. 11.8. Introduce Parameter Object
      1. 11.8.1. Motivation
      2. 11.8.2. Mechanics
    9. 11.9. Remove Setting Method
      1. 11.9.1. Motivation
      2. 11.9.2. Mechanics
      3. 11.9.3. Example
    10. 11.10. Hide Method
      1. 11.10.1. Motivation
      2. 11.10.2. Mechanics
    11. 11.11. Replace Constructor with Factory Method
      1. 11.11.1. Motivation
      2. 11.11.2. Mechanics
      3. 11.11.3. Example
    12. 11.12. Replace Error Code with Exception
      1. 11.12.1. Motivation
      2. 11.12.2. Mechanics
      3. 11.12.3. Example
    13. 11.13. Replace Exception with Test
      1. 11.13.1. Motivation
      2. 11.13.2. Mechanics
    14. 11.14. Summary
  17. 12. Simplifying Generalization Relationships
    1. 12.1. Pull Up Field
      1. 12.1.1. Motivation
      2. 12.1.2. Mechanism
      3. 12.1.3. Example
    2. 12.2. Pull Up Method
      1. 12.2.1. Motivation
      2. 12.2.2. Mechanism
      3. 12.2.3. Example
    3. 12.3. Pull Up Constructor Body
      1. 12.3.1. Motivation
      2. 12.3.2. Mechanism
      3. 12.3.3. Example
    4. 12.4. Push Down Method
      1. 12.4.1. Motivation
      2. 12.4.2. Mechanism
      3. 12.4.3. Example
    5. 12.5. Push Down Field
      1. 12.5.1. Motivation
      2. 12.5.2. Mechanism
      3. 12.5.3. Example
    6. 12.6. Extract Subclass
      1. 12.6.1. Motivation
      2. 12.6.2. Mechanism
      3. 12.6.3. Example
    7. 12.7. Extract Super Class
      1. 12.7.1. Motivation
      2. 12.7.2. Mechanism
      3. 12.7.3. Example
    8. 12.8. Collapse Hierarchy
      1. 12.8.1. Motivation
      2. 12.8.2. Mechanism
      3. 12.8.3. Example
    9. 12.9. Form Template Method
      1. 12.9.1. Motivation
      2. 12.9.2. Mechanism
      3. 12.9.3. Example
    10. 12.10. Replace Inheritance with Delegation
      1. 12.10.1. Motivation
      2. 12.10.2. Mechanism
      3. 12.10.3. Example
    11. 12.11. Replace Delegation with Inheritance
      1. 12.11.1. Motivation
      2. 12.11.2. Mechanism
      3. 12.11.3. Example
    12. 12.12. Summary
  18. 13. Legacy Code
    1. 13.1. Ugly Code
      1. 13.1.1.
        1. 13.1.1.1. index.php
        2. 13.1.1.2. config.php
        3. 13.1.1.3. functions.php
        4. 13.1.1.4. header.php
        5. 13.1.1.5. footer.php
        6. 13.1.1.6. new.php
        7. 13.1.1.7. edit.php
        8. 13.1.1.8. _form.php
        9. 13.1.1.9. remove.php
    2. 13.2. Maintenance
      1. 13.2.1. Example: SQL injection
      2. 13.2.2. Example: Database Portability
    3. 13.3. New Features
      1. 13.3.1. Dynamic Layouts
      2. 13.3.2. Internationalization
    4. 13.4. Break the Cycle
    5. 13.5. Summary
  19. 14. Regression Tests
    1. 14.1. Ugly But Valuable
    2. 14.2. Keeping Value vs. Wasting Value
    3. 14.3. Putting the Chaos in a Cage
      1. 14.3.1. Motivation
      2. 14.3.2. Mechanics
      3. 14.3.3. Examples
        1. 14.3.3.1. Add a New Record
        2. 14.3.3.2. Edit a Record
        3. 14.3.3.3. Read a List of Records
        4. 14.3.3.4. Remove a Record
        5. 14.3.3.5. Validate a Record
        6. 14.3.3.6. Test Refactoring
        7. 14.3.3.7. Unify Test Cases in a Suite
    4. 14.4. Summary
  20. 15. Refactoring with Patterns
    1. 15.1. Design Patterns
      1. 15.1.1. What Are Design Patterns?
      2. 15.1.2. Why Do I Need to Use Design Patterns?
      3. 15.1.3. When Do I Need to Use Them?
      4. 15.1.4. Refactoring with Patterns
    2. 15.2. Transform Procedural Code into Object-Oriented Code
      1. 15.2.1. Motivation
      2. 15.2.2. Mechanism
      3. 15.2.3. Example
        1. 15.2.3.1. Working with Fixtures
        2. 15.2.3.2. Index Action
        3. 15.2.3.3. Add Action
        4. 15.2.3.4. Edit Action
        5. 15.2.3.5. Remove Action
    3. 15.3. Replace SQL with ORM
      1. 15.3.1. Motivation
      2. 15.3.2. Mechanism
      3. 15.3.3. Example
    4. 15.4. Separate Business Logic from View
      1. 15.4.1. Motivation
      2. 15.4.2. Mechanism
      3. 15.4.3. Example
        1. 15.4.3.1. Decorator Design Pattern
        2. 15.4.3.2. Template View Pattern
    5. 15.5. MVC Architecture
      1. 15.5.1. Motivation
      2. 15.5.2. Mechanism
      3. 15.5.3. Example
    6. 15.6. Summary