<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>PHP on ma.ttias.be</title><link>https://ma.ttias.be/categories/php/</link><description>Recent content in PHP on ma.ttias.be</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><managingEditor>mattias@ma.ttias.be (Mattias Geniar)</managingEditor><webMaster>mattias@ma.ttias.be (Mattias Geniar)</webMaster><lastBuildDate>Mon, 22 Jun 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://ma.ttias.be/categories/php/index.xml" rel="self" type="application/rss+xml"/><item><title>Turn your Filament panel into an AI-native dashboard</title><link>https://ma.ttias.be/filament-mcp/</link><pubDate>Mon, 22 Jun 2026 00:00:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/filament-mcp/</guid><description>&lt;p&gt;You can already point an AI agent at your Filament admin panel and have it click around like a human. Take a screenshot, find the button, fill the form, submit, screenshot again to check it worked. With computer-use or a browser MCP, that works today. It&amp;rsquo;s also slow, brittle, and spends a small fortune in tokens describing pixels to figure out where the &amp;ldquo;Save&amp;rdquo; button is.&lt;/p&gt;</description></item><item><title>Lessons learned: don't mix $timeout attributes and properties on queued Laravel jobs</title><link>https://ma.ttias.be/dont-mix-timeout-attributes-and-properties-laravel-jobs/</link><pubDate>Wed, 03 Jun 2026 00:00:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/dont-mix-timeout-attributes-and-properties-laravel-jobs/</guid><description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; the fix described in this post has since been &lt;a href="https://github.com/laravel/framework/pull/60369" target="_blank" rel="noopener noreferrer"&gt;merged into Laravel&lt;/a&gt;
and ships in the next &lt;code&gt;13.x&lt;/code&gt; release. From that release on, a child class&amp;rsquo;s plain &lt;code&gt;$timeout&lt;/code&gt; property correctly overrides an attribute inherited from a parent, so the specific footgun below no longer bites. This post stays up as a historical write-up: how the bug behaved, the subtle PHP reflection edge case behind it, and the fix that closed it.&lt;/p&gt;</description></item><item><title>Catching SQL performance issues in PHPUnit and Pest, as part of your test infrastructure</title><link>https://ma.ttias.be/catching-sql-performance-issues-in-phpunit-and-pest-as-part-of-your-test-infrastructure/</link><pubDate>Mon, 26 Jan 2026 00:00:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/catching-sql-performance-issues-in-phpunit-and-pest-as-part-of-your-test-infrastructure/</guid><description>&lt;p&gt;I&amp;rsquo;ve been on a bit of a SQL performance kick lately. Over at &lt;a href="https://ohdear.app" target="_blank" rel="noopener noreferrer"&gt;Oh Dear&lt;/a&gt;
, I wrote a &lt;a href="https://ohdear.app/news-and-updates/our-3-part-series-on-sql-performance-optimisations" target="_blank" rel="noopener noreferrer"&gt;3-part series about finding, fixing, and automatically detecting SQL performance issues&lt;/a&gt;
. The last part of that series covers how we catch regressions &lt;em&gt;before&lt;/em&gt; they hit production by running checks in our test suite.&lt;/p&gt;</description></item><item><title>A PHP package to simplify working with percentages</title><link>https://ma.ttias.be/php-package-simplify-working-percentages/</link><pubDate>Mon, 01 Jun 2020 00:00:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/php-package-simplify-working-percentages/</guid><description>&lt;p&gt;I created a PHP package that can make it easier to work with percentages in any PHP application.&lt;/p&gt;</description></item><item><title>Build &amp; test your Laravel project via Bitbucket Pipelines</title><link>https://ma.ttias.be/build-test-laravel-project-bitbucket-pipelines/</link><pubDate>Wed, 29 Apr 2020 00:00:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/build-test-laravel-project-bitbucket-pipelines/</guid><description>&lt;p&gt;This post will show you how to use &lt;a href="https://bitbucket.org/product/features/pipelines" target="_blank" rel="noopener noreferrer"&gt;Bitbucket Pipelines&lt;/a&gt;
to build and test your Laravel Project in a docker container.&lt;/p&gt;</description></item><item><title>How I write and curate the cron.weekly newsletter</title><link>https://ma.ttias.be/how-to-cron-weekly-newsletter/</link><pubDate>Wed, 29 Apr 2020 00:00:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/how-to-cron-weekly-newsletter/</guid><description>&lt;p&gt;Every Sunday, I send out &lt;a href="https://ma.ttias.be/cronweekly"&gt;a newsletter called cron.weekly&lt;/a&gt;
to over 10.000 subscribers. In this post, I&amp;rsquo;ll do a deep-dive into &lt;em&gt;how&lt;/em&gt; those mails get delivered to subscribers.&lt;/p&gt;</description></item><item><title>Composer require specific version while ignoring package dependencies</title><link>https://ma.ttias.be/composer-require-specific-version-while-ignoring-dependencies/</link><pubDate>Thu, 16 Apr 2020 00:00:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/composer-require-specific-version-while-ignoring-dependencies/</guid><description>&lt;p&gt;I&amp;rsquo;m working on some new versions of PHP packages, and for that I&amp;rsquo;m working of a temporary branch. I wanted to update my local &lt;code&gt;composer&lt;/code&gt; packages, but ran into a package constraint.&lt;/p&gt;</description></item><item><title>Forcing a Content-Type header with Guzzle's form_params</title><link>https://ma.ttias.be/force-content-type-header-guzzle-form-params/</link><pubDate>Mon, 09 Mar 2020 00:00:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/force-content-type-header-guzzle-form-params/</guid><description>&lt;p&gt;I just lost an hour or 2 of my life to this, so I figure I&amp;rsquo;ll do a small write-up to save &lt;em&gt;future me&lt;/em&gt; from having to do the same dance.&lt;/p&gt;</description></item><item><title>Name your Laravel Horizon workers for easier debugging at the CLI</title><link>https://ma.ttias.be/name-laravel-horizon-worker-easier-debugging-cli/</link><pubDate>Thu, 19 Dec 2019 00:00:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/name-laravel-horizon-worker-easier-debugging-cli/</guid><description>&lt;p&gt;As part of our &lt;a href="https://ohdear.app/" target="_blank" rel="noopener noreferrer"&gt;Oh Dear! monitoring service&lt;/a&gt;
, we run workers. A &lt;em&gt;lot&lt;/em&gt; of workers. Every site uptime check is a new worker, every broken links job is a new worker, every certificate check is a- you get the idea.&lt;/p&gt;</description></item><item><title>A Caddyfile config example for Laravel</title><link>https://ma.ttias.be/caddyfile-config-example-for-laravel/</link><pubDate>Mon, 25 Nov 2019 00:00:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/caddyfile-config-example-for-laravel/</guid><description>&lt;p&gt;I&amp;rsquo;ve been using the &lt;a href="https://caddyserver.com/" target="_blank" rel="noopener noreferrer"&gt;Caddy&lt;/a&gt;
webserver for all my projects lately. Here&amp;rsquo;s my current default config for a Laravel project.&lt;/p&gt;</description></item><item><title>Remove index.php from the URL in Laravel</title><link>https://ma.ttias.be/remove-index-php-from-the-url-in-laravel/</link><pubDate>Thu, 21 Nov 2019 00:00:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/remove-index-php-from-the-url-in-laravel/</guid><description>&lt;p&gt;If you have a Laravel project, you might be surprised to find your routes are probably available on a number of different URLs.&lt;/p&gt;</description></item><item><title>Disable HTTP sessions in Laravel to speed up your API</title><link>https://ma.ttias.be/disable-http-sessions-in-laravel-to-speed-up-your-api/</link><pubDate>Fri, 08 Nov 2019 00:00:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/disable-http-sessions-in-laravel-to-speed-up-your-api/</guid><description>&lt;p&gt;If you run a Laravel application purely as a headless API, you can benefit from disabling the HTTP sessions.&lt;/p&gt;</description></item><item><title>Mac pecl install: configure: error: Please reinstall the pkg-config distribution</title><link>https://ma.ttias.be/mac-pecl-install-configure-error-please-reinstall-the-pkg-config-distribution/</link><pubDate>Wed, 16 Oct 2019 19:26:28 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/mac-pecl-install-configure-error-please-reinstall-the-pkg-config-distribution/</guid><description>&lt;p&gt;I ran into this error when doing a &lt;code&gt;pecl install imagick&lt;/code&gt; on a Mac.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pecl install imagick
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;...&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;checking &lt;span class="k"&gt;for&lt;/span&gt; pkg-config... no
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pkg-config not found
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;configure: error: Please reinstall the pkg-config distribution
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ERROR: &lt;span class="sb"&gt;`&lt;/span&gt;/private/tmp/pear/temp/imagick/configure --with-php-config&lt;span class="o"&gt;=&lt;/span&gt;/usr/local/opt/php/bin/php-config --with-imagick&lt;span class="err"&gt;&amp;#39;&lt;/span&gt; failed
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;By default, the needed &lt;code&gt;pkg-config&lt;/code&gt; binary isn&amp;rsquo;t installed. You can install it via &lt;a href="https://brew.sh/" target="_blank" rel="noopener noreferrer"&gt;Homebrew&lt;/a&gt;
.&lt;/p&gt;</description></item><item><title>Install PHP’s imagick extension on Mac with Brew</title><link>https://ma.ttias.be/install-phps-imagick-extension-on-mac-with-brew/</link><pubDate>Wed, 16 Oct 2019 19:24:07 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/install-phps-imagick-extension-on-mac-with-brew/</guid><description>&lt;p&gt;I was setting up a new Mac and ran into this problem again, where a default PHP installation with &lt;code&gt;brew&lt;/code&gt; is missing a few important extensions. In this case, I wanted to get the &lt;code&gt;imagick&lt;/code&gt; extension loaded.&lt;/p&gt;</description></item><item><title>Laravel’s Tinker quits immediately on PHP 7.3 &amp; Mac</title><link>https://ma.ttias.be/laravels-tinker-quits-immediately-on-php-7-3-mac/</link><pubDate>Mon, 14 Oct 2019 11:46:00 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/laravels-tinker-quits-immediately-on-php-7-3-mac/</guid><description>&lt;p&gt;I had a weird issue with Laravel&amp;rsquo;s &lt;a href="https://laravel.com/docs/master/artisan" target="_blank" rel="noopener noreferrer"&gt;Tinker artisan&lt;/a&gt;
command. Every time I would load it up and type a command, it would immediately quit.&lt;/p&gt;</description></item><item><title>A github CI workflow tailored to modern PHP applications (Laravel, Symfony, …)</title><link>https://ma.ttias.be/a-github-ci-workflow-tailored-to-laravel-applications/</link><pubDate>Thu, 03 Oct 2019 11:45:56 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/a-github-ci-workflow-tailored-to-laravel-applications/</guid><description>&lt;p&gt;Last year we wrote a blogpost about our setup we use for &lt;a href="https://ohdear.app/" target="_blank" rel="noopener noreferrer"&gt;Oh Dear!&lt;/a&gt;
with Gitlab, and &lt;a href="https://ohdear.app/blog/our-gitlab-ci-pipeline-for-laravel-applications" target="_blank" rel="noopener noreferrer"&gt;how we use their pipelines for running our CI tests&lt;/a&gt;
. Since then, we&amp;rsquo;ve moved back to Github since they introduced their free private repositories.&lt;/p&gt;</description></item><item><title>How we used Caddy and Laravel’s subdomain routing to serve our status pages</title><link>https://ma.ttias.be/how-we-used-caddy-and-laravels-subdomain-routing-to-serve-our-status-pages/</link><pubDate>Thu, 19 Sep 2019 10:04:17 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/how-we-used-caddy-and-laravels-subdomain-routing-to-serve-our-status-pages/</guid><description>&lt;blockquote&gt;
&lt;p&gt;We recently launched our new Status Page feature. Under the hood, it&amp;rsquo;s using the Caddy proxy server and Laravel&amp;rsquo;s subdomain routing to serve the right status page on the right domain.&lt;/p&gt;</description></item><item><title>MySQL 8 &amp; Laravel: The server requested authentication method unknown to the client</title><link>https://ma.ttias.be/mysql-8-laravel-the-server-requested-authentication-method-unknown-to-the-client/</link><pubDate>Tue, 19 Mar 2019 09:52:17 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/mysql-8-laravel-the-server-requested-authentication-method-unknown-to-the-client/</guid><description>&lt;p&gt;For local development I use &lt;a href="https://laravel.com/docs/5.8/valet" target="_blank" rel="noopener noreferrer"&gt;Laravel Valet&lt;/a&gt;
. Recently, the brew packages have updated to MySQL 8 which &lt;a href="https://ma.ttias.be/mysql-8-removes-shorthand-creating-user-permissions/"&gt;changed a few things about its user management&lt;/a&gt;
. One thing I continue to run into is this error when working with existing Laravel applications.&lt;/p&gt;</description></item><item><title>Our Gitlab CI pipeline for Laravel applications – Oh Dear! blog</title><link>https://ma.ttias.be/our-gitlab-ci-pipeline-for-laravel-applications-oh-dear-blog/</link><pubDate>Wed, 12 Dec 2018 19:34:23 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/our-gitlab-ci-pipeline-for-laravel-applications-oh-dear-blog/</guid><description>&lt;p&gt;We&amp;rsquo;ve built an extensive Gitlab CI Pipeline for our testing at &lt;a href="https://ohdear.app" target="_blank" rel="noopener noreferrer"&gt;Oh Dear!&lt;/a&gt;
and we&amp;rsquo;re open sourcing our configs.&lt;/p&gt;</description></item><item><title>PHP 7.3.0 Release Announcement</title><link>https://ma.ttias.be/php-7-3-0-release-announcement/</link><pubDate>Thu, 06 Dec 2018 16:11:11 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/php-7-3-0-release-announcement/</guid><description>&lt;p&gt;A new PHP release is born: 7.3!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The PHP development team announces the immediate availability of PHP 7.3.0. This release marks the third feature update to the PHP 7 series.&lt;/p&gt;</description></item><item><title>Deploying laravel-websockets with Nginx reverse proxy and supervisord</title><link>https://ma.ttias.be/deploying-laravel-websockets-with-nginx-reverse-proxy-and-supervisord/</link><pubDate>Tue, 04 Dec 2018 22:18:57 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/deploying-laravel-websockets-with-nginx-reverse-proxy-and-supervisord/</guid><description>&lt;p&gt;There is a new PHP package available for Laravel users called &lt;a href="https://github.com/beyondcode/laravel-websockets" target="_blank" rel="noopener noreferrer"&gt;laravel-websockets&lt;/a&gt;
that allows you to quickly start a websocket server for your applications.&lt;/p&gt;</description></item><item><title>Increase the number of open files for jobs managed by supervisord</title><link>https://ma.ttias.be/increase-the-number-of-open-files-for-jobs-managed-by-supervisord/</link><pubDate>Thu, 29 Nov 2018 18:30:19 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/increase-the-number-of-open-files-for-jobs-managed-by-supervisord/</guid><description>&lt;p&gt;In Linux, a non-privileged user by default can only open &lt;code&gt;1024&lt;/code&gt; files on a machine. This includes handles to log files, but also local sockets, TCP ports, &amp;hellip; everything&amp;rsquo;s a file and the usage is limited, as a system protection.&lt;/p&gt;</description></item><item><title>My Laracon EU talk: Minimum Viable Linux</title><link>https://ma.ttias.be/my-laracon-eu-talk-minimum-viable-linux/</link><pubDate>Tue, 27 Nov 2018 14:01:14 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/my-laracon-eu-talk-minimum-viable-linux/</guid><description>&lt;p&gt;The recorded video of my presentation I gave at Laracon EU last summer.&lt;/p&gt;
&lt;p&gt;The title is, in hindsight, a badly chosen one. I tried to make it a pun on &amp;ldquo;&lt;a href="https://en.wikipedia.org/wiki/Minimum_viable_product" target="_blank" rel="noopener noreferrer"&gt;Minimum Viable Product&lt;/a&gt;
&amp;rdquo; (you know, the &lt;em&gt;startup-y&lt;/em&gt; stuff), but it ended up giving perhaps a false expectation to the audience thinking it was about minimal linux distros, which it wasn&amp;rsquo;t.&lt;/p&gt;</description></item><item><title>Automatic monitoring of Laravel Forge managed sites with Oh Dear!</title><link>https://ma.ttias.be/automatic-monitoring-of-laravel-forge-managed-sites-with-oh-dear/</link><pubDate>Wed, 07 Nov 2018 08:46:49 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/automatic-monitoring-of-laravel-forge-managed-sites-with-oh-dear/</guid><description>&lt;p&gt;Did I mention there&amp;rsquo;s a blog for Oh Dear! yet? :-)&lt;/p&gt;
&lt;p&gt;This week we shipped a pretty cool feature: if you use Laravel Forge to manage your servers &amp;amp; sites, we can automatically detect newly added sites and start monitoring those instantly.&lt;/p&gt;</description></item><item><title>How to size &amp; scale your Laravel Queues</title><link>https://ma.ttias.be/how-to-size-scale-your-laravel-queues/</link><pubDate>Tue, 06 Nov 2018 07:31:23 +0000</pubDate><author>mattias@ma.ttias.be (Mattias Geniar)</author><guid>https://ma.ttias.be/how-to-size-scale-your-laravel-queues/</guid><description>&lt;p&gt;We&amp;rsquo;ve got a new blog set up for our &lt;a href="https://ohdear.app/blog" target="_blank" rel="noopener noreferrer"&gt;Oh Dear!&lt;/a&gt;
monitoring service. In it, we share some details of our setup, how we tackle technical challenges and how we implement some of our monitoring tooling.&lt;/p&gt;</description></item></channel></rss>