The tools you choose shape how quickly you spot problems, how confidently you refactor, and how reliably you ship. This page covers the development tools that matter most in professional PHP work, from the editor you write code in to the static analysers that catch mistakes before runtime, the debugger that shows you what actually happens, the testing frameworks that prove your code works, and the dependency manager that holds it all together. The focus is on tools that earn their place in a real workflow, not on listing every option available. Below you will find sections on code editors and IDEs, static analysis with PHPStan and Psalm, debugging with Xdebug, testing with PHPUnit and Pest, dependency management with Composer, code style enforcement, and build tooling.
For the broader set of resources that complement the book and guides, see the Resources hub.
Code Editors and IDEs
Two options dominate PHP development: PhpStorm and Visual Studio Code with PHP extensions.
PhpStorm is purpose-built for PHP. It understands the language natively, meaning code completion, refactoring tools, and navigation work without extra configuration. PhpStorm parses your entire project, resolves class hierarchies across files, understands PHPDoc annotations, and provides inline type information. The built-in Xdebug integration means you can set breakpoints and step through code without leaving the editor. Database tools, HTTP client, terminal, and version control are all integrated. For developers working on large codebases, the “find usages” and “refactor rename” features save hours of manual searching. PhpStorm is a commercial product with a subscription model.
Visual Studio Code is free, fast, and extensible. It does not understand PHP out of the box, but the Intelephense extension provides code completion, go-to-definition, find references, and diagnostics that approach what PhpStorm offers. PHP Debug adds Xdebug support. The extension model means you can assemble exactly the set of features you need, though the integration between extensions is not always as seamless as a purpose-built IDE.
The practical difference comes down to project size and team standards. On a large Zend Framework application with hundreds of classes, PhpStorm’s deep index and refactoring tools pay for themselves quickly. On smaller projects or when working across multiple languages, VS Code’s lighter footprint and flexibility are appealing.
Whichever you choose, invest time in learning the keyboard shortcuts for navigation: go to definition, find usages, navigate back, search by symbol name. These shortcuts eliminate most of the friction of moving through a large codebase.
Static Analysis: PHPStan and Psalm
Static analysis tools read your PHP code and find bugs without running it. They catch type mismatches, undefined methods, impossible conditions, dead code, and dozens of other problems that would otherwise surface as runtime errors or silent data corruption.
PHPStan operates on a level system from 0 (most permissive) to 9 (strictest). At level 0, it catches obvious mistakes like calling methods on non-objects and using undefined variables. At level 5 and above, it starts checking argument types, return types, and generic type parameters. Most teams start at level 0 or 1 on an existing codebase, fix all reported issues, then increment the level over time.
PHPStan is configured through a phpstan.neon file at the project root:
1 | parameters: |
Psalm takes a similar approach with a different type inference engine. Psalm excels at taint analysis, where it tracks data flow from user input through your application to detect potential security issues like SQL injection or cross-site scripting. Psalm uses a psalm.xml configuration file and its own error level system.
Both tools support custom extensions and baseline files. A baseline file records all existing errors so you can enforce “no new errors” without fixing the entire codebase at once. This is critical for adopting static analysis on a project with years of accumulated type issues.
For projects built on Zend Framework 1, where type annotations are sparse and the underscore-based autoloading predates modern conventions, starting at a low level with a large baseline is the realistic approach. The goal is to improve coverage incrementally, just like the strategy described in the Modernising Zend Framework Applications guide.
Debugging with Xdebug
print_r and var_dump are debugging tools in the same way that a hammer is a screwdriver: they work in a pinch, but they are the wrong tool. Xdebug is the proper debugger for PHP, and it changes how you understand your code.
Xdebug 3.x is configured through php.ini:
1 | [xdebug] |
With start_with_request=trigger, Xdebug only activates when it receives a trigger cookie or query parameter. This means you can leave it installed in your development environment without incurring overhead on every request. A browser extension toggles the trigger.
Once a debugging session starts, you can set breakpoints, step through code line by line, inspect variable values at any point in the execution, and evaluate expressions in the current scope. For understanding how a request flows through a Zend Framework application, from the front controller through the dispatch loop to the controller action and back, stepping through with Xdebug is the fastest way to learn the architecture. The concepts in the Architecture chapter become concrete when you watch them execute.
Xdebug also provides profiling capabilities for performance work. The PHP Performance Playbook covers the profiling workflow in detail, including how to read cachegrind output and identify hot paths.
Testing: PHPUnit and Pest
Automated testing is the tool that lets you change code with confidence. Without tests, every refactoring is a gamble. With tests, you know within seconds whether a change broke something.
PHPUnit is the standard testing framework for PHP. It provides assertions, test doubles (mocks and stubs), data providers, code coverage reporting, and integration with CI pipelines. A phpunit.xml file at the project root configures test directories, bootstrap files, and coverage settings.
A basic PHPUnit test:
1 | class EntryServiceTest extends TestCase |
Pest is built on top of PHPUnit and provides a more expressive syntax. It uses closures instead of classes and methods, which reduces boilerplate and makes tests read more like specifications. Pest is fully compatible with PHPUnit: you can mix Pest test files and PHPUnit test classes in the same suite, and all PHPUnit assertions work inside Pest tests.
The same test in Pest:
1 | it('persists entry to repository', function () { |
For Zend Framework applications that have no tests at all, the Modernising Zend Framework Applications guide covers the practical steps of adding tests to existing code, including characterisation tests that capture current behaviour before you start changing anything.
Dependency Management with Composer
Composer is the dependency manager for PHP. It resolves package versions, downloads them, and generates an autoloader that maps namespaces to directories. Every modern PHP project uses Composer, and even projects that predate it can adopt it incrementally.
Key commands:
composer require vendor/packageadds a dependencycomposer updateresolves and downloads the latest compatible versionscomposer installinstalls exact versions fromcomposer.lockcomposer dump-autoload --optimizegenerates an optimised classmap autoloader for production
The composer.lock file is critical: it records the exact version of every installed package so that every developer and every deployment gets identical dependencies. Always commit composer.lock to version control.
For ZF1 projects that originally managed dependencies manually, introducing Composer is one of the first modernisation steps. The process involves creating a composer.json, adding a classmap entry for the existing library directory, and gradually moving to PSR-4 autoloading as new code is written under modern namespaces. The Installing the Zend Framework chapter shows the original installation approach, and the modernisation guide shows how to move beyond it.
Code Style: PHP-CS-Fixer and PHP_CodeSniffer
Consistent formatting eliminates an entire category of code review discussion and reduces diff noise. Two tools handle this for PHP.
PHP-CS-Fixer applies a defined set of rules to reformat your code. Configure it with a .php-cs-fixer.dist.php file that specifies which rules to apply and which directories to scan. Running php-cs-fixer fix reformats your codebase to match the rules. Common rule sets include PSR-12 and the Symfony coding standard.
PHP_CodeSniffer takes a slightly different approach: phpcs reports violations against a coding standard, and phpcbf fixes them automatically where possible. It ships with built-in support for PSR-1, PSR-2, PSR-12, and several framework-specific standards.
In practice, teams pick one tool and run it as a pre-commit hook or CI step. The goal is that formatting never comes up in code review because it is handled automatically.
Build Tools and Task Automation
PHP projects sometimes need build steps beyond what Composer provides: compiling frontend assets, generating API documentation, running database migrations, or orchestrating multi-step deployment sequences.
Make remains practical for PHP projects. A Makefile with targets like make test, make analyse, and make deploy gives the team a consistent interface regardless of what runs underneath. Developers do not need to remember the exact phpunit or phpstan command with all its flags.
Composer scripts fill a similar role. The scripts section in composer.json can define commands like composer test and composer analyse that run the underlying tools with the correct arguments. This keeps the configuration in the same file that manages dependencies.
For projects that include frontend assets, tools like Webpack, Vite, or esbuild compile JavaScript and CSS. The Design chapter covers view layer integration, and the same principles apply when connecting modern build tools to a PHP backend.
Putting It Together
The tools on this page work best as a chain. Composer manages your dependencies and autoloading. Your editor provides navigation and inline feedback. PHPStan or Psalm catches type errors and logic problems statically. PHPUnit or Pest verifies behaviour. Xdebug helps you understand what happens at runtime. PHP-CS-Fixer or PHP_CodeSniffer keeps formatting consistent. A Makefile or Composer scripts tie the chain together so that running the full suite is a single command.
The investment in setting up this toolchain pays off every day. Each tool removes a category of problem that would otherwise consume your attention during development and review. For further reading on how these tools fit into a broader PHP development workflow, explore the PHP topic hub and the guides section.