---
title: 'Fix PHP Performance Issues in Third-Party Code with Composer Patches'
source: 'https://youtube.com/watch?v=TWBxB4-kpck'
video_id: 'TWBxB4-kpck'
date: 2026-08-03
duration_sec: 653
---

# Fix PHP Performance Issues in Third-Party Code with Composer Patches

> Source: [Fix PHP Performance Issues in Third-Party Code with Composer Patches](https://youtube.com/watch?v=TWBxB4-kpck)

## Summary

This video demonstrates how to use Composer patches as a last resort to fix performance issues in third-party PHP code, specifically applying a patch to Doctrine DBAL to improve Shopware 6 performance. The presenter shows the installation of the composer-patches plugin, creating and applying a patch, and measuring the performance improvement.

### Key Points

- **Problem: Plugins Often Have Performance Issues** [00:02] — Plugin authors often don't prioritize performance, making it necessary to patch third-party code. Composer patches is a solution for projects using Composer.
- **Composer Patches is a Plugin, Not Core** [01:16] — Composer patches is a plugin that is not shipped by Composer itself. It allows loading patches from remote sources, but this is dangerous.
- **Warning: Avoid Remote Patches** [01:28] — Loading patches from remote sources (e.g., GitHub gists) is dangerous because code can change at any time. Always use local patches that are part of your project and can be vetted.
- **Warning: Voiding Support** [02:10] — Patching third-party libraries voids their support and guarantee. You must perform your own tests to ensure the patched code works as intended.
- **Example: Doctrine DBAL SQL Parser Patch** [02:42] — The video applies a patch to Doctrine DBAL's SQL parser to improve Shopware 6 performance. The patch combines multiple regular expressions into one using named capture groups.
- **Installing Composer Patches Plugin** [03:11] — The plugin is installed via Composer. Version 2 is in beta, so you need to specify the exact version. The command asks for trust to execute scripts.
- **Creating the Patch File** [04:00] — The patch is obtained from a GitHub pull request by appending '.patch' to the URL. The patch is saved in a 'patches' directory.
- **Modifying composer.json** [05:39] — In the 'extra' section, add a 'patches' key, specify the library (doctrine/dbal), and provide a description of the patch.
- **Benefits of Patching** [06:20] — Patching allows pulling performance fixes into older versions without a full upgrade, which might break other things. It's a way to get benefits earlier.
- **Applying the Patch** [07:07] — Run 'composer patches relock' to apply patches. Then 'composer patches repatch' without scripts to reinstall the library and apply the patch cleanly.
- **Result: Simplified Code** [07:53] — The patched code uses a combined token pattern with named capture groups, making the parse method simpler and faster.
- **Performance Improvement Measured** [08:24] — Using call graphs, the parse method took 24ms before the patch and 10ms after, a ~50% improvement. The combined preg_match replaces three separate calls, and the closure indirection is removed.

### Conclusion

Composer patches are a powerful last-resort tool for fixing performance issues in third-party code, but they must be used carefully with local patches and thorough testing. The example shows a significant performance gain with minimal effort.

## Transcript

plugins is a major source of pain for developers working with Magento, Shopware, WordPress or other customizable off-the-shelf PHP applications. Mo, I am Benjamin and in this video I'm going to show how to use
composer patches as a last resort to fixing performance problems in third party code. I show how to install the composer patches plugin and an example from doctrine debal that improves Shopware 6 performance. It's a sad but
common truths. Plug-in authors more often than not are not interested improving the performance of their code. That makes it necessary to sometimes patch the code from third-party plugins. And one way of doing that in projects
that are using composer to install thirdparty plugins is the composer patches plugin. You can find an example of using composer patches to fix performance in thirdparty libraries on our tidebase blog. There I also link to
the composer patches plugin on GitHub. Um and the project also has its own website that you can look at with information on the plug-in. This is not information on the plug-in. This is not a primary composer functionality but
acts as a plug-in that is not shipped by the composer author itself. There's also a huge word of warning that I need to issue about this. Composer plugins has a
feature that allows you to load patches from remote sources. for example, from a from remote sources. for example, from a GitHub gist or any other remote URL dynamically during uh installation of a project. I don't recommend using this
remote approach because it's really dangerous to dynamically load code from an unvetted source especially if the code can be changed uh at any point in
time. You should always use composer patches in local mode. That means the patches are part of your um project and you can vet those patches. Even if you're using patches to change third party libraries, there's
still a word of warning I have to issue. You're obviously breaking all guarantee seals and voiding um sort of the support of a third party library that they have tested their code um to be bug free or as buckree as possible. you should uh
perform your own tests with the patched code to make sure it works as intended. For this video, we are going to look at the doctrine debal SQL parser patch again that I talked about in a previous video. Here we are going to apply this
patch to an existing Shopware installation to see how we can make use of composer patches. doctrine debal is usually a well-maintained library and you can upgrade it using composer directly. I'm
just show going to show this uh to demonstrate how composer patches can work. Following along uh my blog post, we see how we can install the composer plugin. I'm going to copy the
instructions. Currently, composer patches uh version two is in beta. That means we need to uh specify the exact version you want to install. If you're watching this video, maybe check if there's still beta 2, the most recent
version, or you need to use a different version to install version to install it. Switching over to PHP Storm, we are uh entering the composer command to install this plugin.
It asks us if we u trust the plugin to execute uh scripts and we do uh say yes. execute uh scripts and we do uh say yes. The plugin is going to be installed. When the installation is finished, we uh add a patch
finished, we uh add a patch to the library. Let's look over the code of um the class that we want to patch again shortly to uh remind us of what we're doing here. The SQL parser of doctrine
doctrine um had an inefficient way of parsing SQL statements by uh running several regular expressions
on the string independently over and over again calling prep match for each individual um regular expression. Uh the patch that we are going to apply is combining this regular expression in a into a single
regular expression and using named capture groups to differentiate which of the different patterns was matched uh at any single time a point of time when the
uh regular expression was applied. We can grab that patch directly from GitHub uh going to the pull request on the doctrine data repository appending.patch patch to the URL. We get the git compatible patch. I copy this
over. Um, go back to PHP Storm. In PHP Storm, I have a patches Storm. In PHP Storm, I have a patches directory. I create a new patch
here. Doctrine Doctrine BalSQL parser pong patch.
pasting the code in there. The next step is to modify the composer JSON file. In the extra section, we add a new
patches and we specify which composer library we and we specify which composer library we are going to patch. doctrine debal
are going to patch. doctrine debal and then we specify another key value pair explaining what the patch is about. SQL paser 3.10 improvement. So in this case we are pulling along a performance fix uh into
pulling along a performance fix uh into a um an older version just to uh get the a um an older version just to uh get the benefit earlier um than uh updating to
be necessary if the changes from the current version you're on to the version with a fix are too big and they break other things in your application. This way you can partially uh pull code from u more recent versions into your
project. Uh especially for performance fixes. This is a really nice way of um possible. To apply this new patch to the project, we run a command that uh the plug-in provides to composer. So composer
patches relock applies all the patches. Again, after locking the patches, we can look at the patches.lock pong JSON to see that the doctrine debal patch that we applied uh was registered. We then run composer patches repatch without
run composer patches repatch without scripts and it will uninstall doctrine debal reinstalled it again and then apply the patch to have a clean version. We can see that here and after it has optimized the
autoloader we can go back to the paza.php and see that the code has paza.php and see that the code has changed to the uh code from the patch. It includes the token pattern with the named capture groups now. And the code
in parse is much much simpler. Just executing the P match with this combined token and then based on the named capture group calling different methods capture group calling different methods on the passing visitor. And uh this will
improve the performance of uh this API quite a lot because there are just so much fewer functions being called and those functions that are called like PR match are not called multiple times anymore uh on each different patterns
but using this combined pattern. Let's quickly look at the call graph to see how this change affects a real world shopperware installation. We are searching for the pasa parse method in the core graph data. And in um
a request that was before the patch, this took 24 milliseconds. And we can look at all the methods being called here. The closure um that delegates to the visitors um is quite expensive. But we can also see multiple PM match
different pack match calls here as well as the calls to key and current that are necessary to control how the Y loop worked in the previous
code. Let's compare this to a trace afterwards. I've generated one uh in preparation before here
and looking at a difference of both traces again using the parer parse traces again using the parer parse method we can see that in the improved method we can see that in the improved request it took 10 milliseconds less
meaning from 24 10 milliseconds almost 50% improvement and if we look at the 50% improvement and if we look at the changes here. We see there's a new method call for the PR match uh with the named capture groups. This PR match
takes 2 seconds and it replaces three P match calls that we had before match calls that we had before um for um again also almost 2 seconds individually. So we have an improvement here. Then we don't need to call key and
current anymore. Also, we don't need to uh call the closure anymore. Instead, the new code calls directly the visitor methods except other except name parameters. And because the indirection of the closer is gone, this also
improves the code a little bit. If you're interested in more detail on how to combine regular expressions and use named capture groups, you can watch this video here on our channel explaining the SQL paraser improvement in detail or
watch any other video uh on our channel on topics of PHP performance improvements. Thank you very much for watching.
