Articles about Software Architecture, Test Automation, and PHP
In-depth perspectives on architecture, modernization, quality, and professional software development.
When the diff is free
Symfony Language Tools no longer accepts pull requests, and most Laravel packages no longer accept issues. Both decisions rest on the same premise: the diff has become cheap. What remains scarce is an understanding of the problem, and the contribution that carries it best is a failing test.
Confidence is not transferable
After my experiment with AI-generated code, I came across three observations: organisational, individual, and generational. Together they point to an uncomfortable conclusion, and to the skill that will matter most in the AI era.
Repetition and Insight: What is new in PHPUnit 13.3?
Reliably detecting flaky tests and tolerating them in a controlled way, code coverage through the lens of your classes, branch and path coverage made visible, and a filter by test size: I walk you through what is new in PHPUnit 13.3.
How PHP generates machine code
The JIT is not switched on in any default installation. Switching it on is a bet that the compiled code runs long enough to earn the compilation back. On a test suite of 177 tests the function JIT loses that bet, and the tracing JIT wins it.
How PHP optimises bytecode
OPcache is called a cache, but it does more than keep bytecode around: fifteen passes sit between the compiler and the executor and rebuild it. I watch them at work and measure how much of it survives into the run time.
How PHP executes bytecode
Which compiler built your PHP binary is a performance decision: until PHP 8.5, a PHP built with Clang was up to 44 % slower than one built with GCC, depending on the benchmark. The difference is entirely in how the executor gets from one instruction to the next, and the Zend Engine has five models for that.
A language has non-functional requirements, too
Nobody decides whether a language is modern. What gets decided is whether you can bet a decade on it: who owns it, how upgrades arrive, how it scales, and whether you can still hire for it in year six. This article holds PHP to the criteria an architecture decision is actually made on.
Four out of five
How does PHP in 2026 compare with the current ideas about designing modern languages? This article takes stock of the criteria of closures, objects, pattern matching, generics, and an unconventional answer to the question of extensibility.
Your composer.lock knows what a carmaker only guesses
A car manufacturer lists an Android botnet in its open source attribution. The entry gives away how the list was made: by scanning instead of by declaring. Why a declared dependency list is worth more than a scanned one, and how the PHPUnit PHAR discloses its own contents.
When static analysis runs your code
A security vulnerability in PHPCSUtils revealed an eval() call in a static analysis tool. Why disable_functions cannot reach eval(), and what a switch in the PHP engine to disable it could look like.
Untouched tests are half the proof
My favourite kind of bug fix only adds a new regression test and leaves every existing test untouched. I checked this claim against PHPUnit's own history: I learned the most from the counterexamples.
Composer and Packagist under supply chain stress
2025 and 2026 proved to be a stress test for the supply chains of all package ecosystems. A review of Composer and Packagist: what PHP does well, what it can learn — and who owns our infrastructure.
Stories about systems that resist people
Five of the best television series I have ever seen are about the gap between what people want to achieve and what institutions allow them. They fascinate me because, after decades of developing Open Source software, I know much of this from my own working life.
Precision and Clarity: What is new in PHPUnit 13.2?
Selecting exactly the tests you want, finer control over the order they run in, faster and clearer output when they fail, and more expressive test doubles: I walk you through what is new in PHPUnit 13.2.
Merging code coverage data
Merging code coverage data from parallel CI jobs has long been fragile and error-prone. These problems are finally solved.
What your test run already knows
On every run, PHPUnit knows how long each test took, how much memory it used, and why it failed. Most of that evaporates. otr-report reads it back out of the Open Test Reporting logfile and puts it within reach.
Speed as a security feature
How fast is your test suite, and what vulnerabilities does an LLM agent therefore fail to detect? What was long considered a productivity issue is now part of the security debate.
Turbo-Charging Your PHPUnit Suite
Slow tests destroy flow, kill TDD, and erode trust until nobody runs the suite. The fix has four tiers, and the biggest wins come from test design, not from infrastructure or parallelisation.
Test-Driven Security
For every vulnerability we find in production, there is a test that, had it existed, would have prevented it. Test-Driven Security treats the CWE list as a checklist and PHPUnit as the tool we already have in our workflow.
Debugging as a design goal
Why do some bugs feel like a short detective story, while others feel like a never-ending thriller? I show you which decisions make your software debuggable.
Code I do not have does not cause any problems
Not every problem requires new code. And every line we do not write is a line that will not cause any problems.
The attack surface begins in the repository
We protect what exists. But do we ask often enough whether it should exist at all? How removing unused branches can protect against Poisoned Pipeline Execution.
Hardening GitHub Actions workflows
A walk through the GitHub Actions weaknesses in PHPUnit's workflows, how each one could have been exploited, and what was changed to close them.
ComoCamp 2026
Three days in Vienna, three days of ComoCamp: my report on inspiring workshops, exciting open space sessions, and the uniquely open, collaborative atmosphere.
Closures, Clarity, and Control: What is New in PHPUnit 13.1?
Closures as data providers, richer Open Test Reporting, custom issue trigger resolvers, and significant changes to code coverage: I walk you through the changes.
Technical debt is not malice
Technical debt is not malice, it is context. An argument for why empathy is a technical skill that matters more than you think.
Debugging Performance in PHP
"It feels slow" is not a diagnosis. I explain the three disciplines that turn vague complaints into actionable data: tracing, profiling, and benchmarking.
The Bouncer in the Dependency Resolver
Composer 2.9 moved security advisory enforcement from an opt-in third-party package into the resolver itself. This article walks through how the mechanism works, how it relates to the older packages it replaces, and where it can bite you.
Everything we have
In a world with endless possibilities for code to be wrong, one approach alone is not enough to make our software truly robust.
Security through chaos
This practical deep dive into the philosophy behind "security through chaos" shows that security does not come from perfect foresight, but from surviving chaos.
Beyond Best Practices
Testing, code reviews and documentation are all essential prerequisites that constrain the autonomy of AI, thereby safeguarding human agency in software development.
Effective Code Reviews
Pair, pull, or post-push? Find the code review strategy that is right for your team.
Faster than understanding
An AI coding agent implemented a complex software metric in 15 minutes. I have now spent hours trying to figure out whether the implementation is correct. Is this really a productivity boost?
From anti-pattern to clarity
The any() matcher is deprecated. But migration is easier than you think – and leads to better tests.
Better than withConsecutive()
I explain how PHPUnit 13's parameter set matchers finally solve the problem that made upgrading to PHPUnit 10 such a challenge.
Replay Testing
Replay Testing leverages the memory of your event sourcing system to test new versions with real history and shows which oracles truly inspire confidence in your changes.
From Events to Insights
Event Storming, DDD, CQRS, and Event Sourcing are intertwined: the tests not only check the events, but also become living documentation and a bridge between technical expertise and code.
How my understanding of software changed
A classic database only stores the "now" and forgets history. In this article, I describe my journey to DDD and event sourcing and explain why we need to learn to model time itself.
Data Provider or Properties?
One test, hundreds of inputs, and an automatic edge case search. But property-based testing has a hidden pitfall that many overlook.
Smaller input, greater insight
Shrinking is the unsung hero of property-based testing. I show you how it helps to make inevitable errors understandable.
Property-Based Testing
We only test what we think of. That is precisely what can become a problem.
Open Source, Open Feeds: Mastodon and PeerTube as online spaces for the PHP community
With phpc.social and phpc.tv, the PHP community is building its own donation-funded online spaces in the Fediverse – free from algorithms and fascist tech bros.
Type-Safe Collections
Does PHP really need generics? A controversial thesis with a practical solution.
How PHP and its ecosystem test each other
PHP tests Laravel, Symfony, PHPUnit, and more every night. PHPUnit tests PHP. This is Open Source collaboration at work.
The Stub/Mock Intervention
Self-sabotaging mock objects? With PHPUnit 12.5, that's a thing of the past because the test runner now asks the right question: Do you really need a mock object, or would a test stub suffice?
A festive break
I take a break from my weekly articles and invite you to a free online event where I will present the latest improvements to PHPUnit.
A flight recorder for your code
Your PHP project has no tests and an upgrade is pending? The classic dilemma: to introduce tests, you have to change code – to change code, you need tests. How can you break this cycle? With characterisation tests.
Seeing the Truth: Test Oracles
Your tests are successful. But are they really? Without a suitable test oracle, you will never know.
Testing with DTOs and Value Objects
Know the differences between data transfer objects and value objects and understand why immutability helps with testing.
Testing with(out) dependencies
Why distinguishing between test stubs and mock objects in PHPUnit significantly improves the quality and readability of tests.
Path Coverage or Mutation Testing?
How thoroughly do your tests cover the code, and how reliably do they detect real errors? I show you how to find out.
Open Source Blackout
Are you prepared for a world in which your projects freeze, deployments stall, and tech giants can no longer rely on free community-run infrastructure?
More control, less friction: What's new in PHPUnit 12.4?
Discover how PHPUnit 12.4 helps you get there with less friction and more insight.
Modern PHP Development
Modern PHP development combines proven principles with the latest tools. It brings together documentation, quality, automation, and AI.
A look ahead to 2035
I discuss key issues for the future relating to ethics, digital sovereignty, Open Source, and web standards.
PHPUnit features that surprise even professionals
Discover the hidden capabilities of PHPUnit and learn how to get the most out of your tests with clever features.
From AmigaBASIC to AI
A personal journey from my first lines of BASIC on the Amiga to the question of how AI will shape the next generation of developers.
Innovation through collaboration: The highlights of PHPUnit 12.3
Discover how collaboration with real-world developers has shaped the latest advancements in PHPUnit 12.3.
Psalm or PHPStan?
Psalm or PHPStan: which tool is the better choice for code analysis? Or is it worth combining both tools for maximum code quality?
30 Years of PHP, 25 Years of PHPUnit
Thirty years of PHP and open-source innovation, viewed through a quarter-century of PHPUnit.
ComoCamp 2025
I am thrilled by the inspiring workshops, exciting open space sessions and the uniquely open, collaborative atmosphere of ComoCamp.
SoCraTes 2024
SoCraTes has enriched and motivated me in a lasting way through inspiring discussions, exciting sessions on topics such as PHP, software testing, security and open-source funding, as well as the special, collaborative atmosphere.
PHP_CodeSniffer or PHP-CS-Fixer?
Should PHP_CodeSniffer or PHP-CS-Fixer be used to get code "in shape"? Should both tools even be used together?
PCOV or Xdebug?
Should you use PCOV or Xdebug to collect code coverage data? Sebastian Bergmann gives a personal answer.
PHPUnit Code Sprint: March 2024
Lessons and impressions from the PHPUnit project’s most recent code sprint.
O Brother, where art thou?
Why isolated changes often fail to deliver the desired result—and why sustainable improvement requires a view of the whole system.
Domain-Driven Design with PHP
More focus on the domain: You should know and be able to apply these design patterns from Domain-Driven Design.
PHP 7: Security Support Ends. Now what?
Security support for PHP 7 has ended. What does this mean for you?
How I manage test fixture
Why test fixtures can be clearer and more reliable without traditional setUp() methods.
How do you name constructors?
PHP does not support constructor overloading. Named constructors provide a remedy. But what is the best way to name them?
Ready Or Not, Here It Comes
Is your software ready for PHP 8.1? Now is the time to find out.
Ready, Preload, Go
Preloading can significantly improve performance. Let's see how it works.
Ketchup or Mayo?
A French fries stand offers a few dishes and drinks. That means founding can't be particularly difficult, can it?
Athletes and Software Development
Do you know the difference between software developers and professional athletes?
Do not mock what you do not own
Programming is all about abstraction. But there is a big difference between owning an abstraction and using somebody else's.
Happy 25th Anniversary, PHP!
Happy 25th anniversary, PHP. Your birthday present arrived just in time.
Caching makes everything faster. Right?
An unexpected PHPUnit problem and the broader lesson hidden inside it.
Unfortunately we have no framework
A framework of your own, or better a standard solution? We approach the question by looking at the history of PHP frameworks.
Developer wanted, maintainer found?
It is very difficult to find good developers. Ever tried to look for a maintainer instead?
Failing IT Projects
What failed IT projects can teach us—and how to turn those lessons into better decisions.
Who wound the clock?
Why PHPUnit no longer relies on the system clock—and what that changes for tests.
High-Resolution Monotonic Timer
We explain why looking at the clock may not be a good idea when you want to measure time.
Goodbye, IT Conference
With the coronavirus pandemic raging, the future of IT conferences is at stake. Or is it?
Improve Your Design with CQRS
Getters read and setters write. What happens when you apply this idea to the architecture of an application?
Automating Edge Cases
The coronavirus pandemic keeps pushing the boundaries of what we consider "edge cases". This leads to interesting IT problems.
PHPUnit: A Security Risk?
Why PHPUnit does not belong on a web server—and which security risk that avoids.
Migrating to PHPUnit 9
A practical path from PHPUnit 8 to PHPUnit 9, including the migration issues to expect.
Help! My tests stopped working
How to make major PHPUnit upgrades predictable and avoid unnecessary frustration.
Blast from the Past
Honestly, we did not expect to ever write about PEAR again. Yet here we are.
Who pays for PHP?
With no formal backing by any company or non-profit organisation, who pays for the development and maintenance of PHP - and how?
Faster Code Coverage
How focused optimizations made PHPUnit’s code coverage analysis significantly faster.
The Future of Zend
Some pivotal persons have announced that they are going to leave Rogue Wave. Is the future of PHP at stake?
Indirect Invocation Considered Harmful
There is a bug in PHP that allows bypassing type safety checks. You would not do that, though, would you?
Putting PHP 8 on the Roadmap
Some problematic PHP features are scheduled for removal in PHP 8. If you are dealing with Unicode strings, you may need to act now.
Why Magic Quotes are gone in PHP 7
Why PHP 7 removed Magic Quotes, what changes during migration, and how applications can handle input safely without the legacy feature.
Microservices for Lunch
Getting the decomposition right is a crucial success factor for microservice architectures. Here is why.
Conferences: for Fun or Profit?
How much money conference speakers in the PHP community actually make.
Don't call instance methods statically
In PHP 7, instance methods cannot be called statically any more. We explain how to deal with this.
Why Developers Should Not Code
A surprising answer to the question why program code is so hard to understand.
Testing Keeps Me From Getting Things Done
Writing unit tests takes time. Is it really worth the effort?
The Death Star Version Constraint
Why overly broad version constraints can break builds—and how to avoid that risk.
Refactoring to PHP 7
How do you adapt an existing codebase to PHP 7, and what are the benefits? Our friend Tim talks about his experiences when getting an e-commerce platform ready for PHP 7.
PHP 5: Active Support Ends. Now what?
Active support for PHP 5 has ended. What does this mean for you?
Typed Arrays in PHP
As a community, we can only make progress when somebody pushes the boundaries. This can be done by questioning established best practices, or by coming up with new ideas.
Questioning PHPUnit Best Practices
Best practices are not set in stone and need to be questioned and then adapted, if need be, every once in a while.
How to Validate Data
Validating data seems to be one of the most important tasks of an application. After all, you cannot trust data from external sources.
On Hackathons
Hackathons are fun and very educational. But do they teach the right values?
Dependencies in Disguise
Passing around a service locator is a bad practice. But how can it be avoided?
20 Years of PHP
How an early encounter with PHP became a long-term commitment to better software design.
20 Years of PHP
How an early encounter with PHP grew into decades of work on its ecosystem.
PHP Breaks Backwards Compatibility
For a major release such as PHP 7, some backwards compatibility breaks are expected to happen. Breaks like these are always a double-edged sword.
Joomla PHPUnit Code Sprint
How a focused code sprint strengthened Joomla’s automated testing.
SoCraTes 2014
My first SoCraTes: a World Café on Thursday, two days of Open Space on TDD, legacy code and apprenticeship, and a board game whose objective looks suspiciously like that of a software project.
TYPO3 PHPUnit Code Sprint
How a focused code sprint improved PHPUnit support in TYPO3.
Disintegration Testing
What NASA’s Mars Climate Orbiter teaches us about test scopes and blind spots.
Continuous Integration
At what project size is continuous integration worthwhile in PHP projects?
Man Is What He Eats
What development teams can learn from a professional kitchen about quality and collaboration.
Educating Children
What watching children learn can teach us about curiosity, feedback, and software development.
Integration Testing
How integration tests bridge the gap between unit and system tests by verifying interfaces and collaboration between components.
Urban Legends and Error Handling
We have all heard those stories that begin with "I know somebody" or "I have heard of somebody" before. Are they true, or just an urban legend?
Trust
How explicit quality goals shape architecture—and why blind trust is a dangerous substitute.
Level Crossings and Traffic Jams
What urban traffic planning can teach us about experiment-driven development.
Software Development Fluxx
What the card game Star Fluxx reveals about agility, object-oriented design, and quality assurance.
Data, Persistence, and My Frying Pan
What a frying pan can teach us about relational and non-relational data stores.
When it gets hot
What a failing train air conditioner reveals about service levels, scalability, and performance goals.
Spaces or Tabs?
Developers are nice people. Just remember to never ask a group of developers which operating system is the best, or whether spaces or tabs should be used for indentation.
Sixty Percent Quality
What hotel ratings can teach software teams about measurable, shared quality goals.
Seeing the Bigger Picture
What thousands of years of building architecture can teach us about structure, engineering, and the still-young discipline of software development.