PHP
Setting up VS Code
Install PHP and XDebug
First install the software. This was done in the WSL
sudo apt install -y php8.5 php8.5-cli php8.5-common php8.5-mbstring php8.5-xml php8.5-curl php8.5-mysql
sudo apt install php-xdebug
Check your php now has Debug. You should see Xdebug listed
php -v
Copyright (c) The PHP Group
Built by Debian
Zend Engine v4.5.3, Copyright (c) Zend Technologies
with Xdebug v3.5.0, Copyright (c) 2002-2025, by Derick Rethans
with Zend OPcache v8.5.3, Copyright (c), by Zend Technologies
Change Your Xdebug.ini
Find you wsl ip with
hostname -I
172.28.58.213
Find your xdebug.ini
php -i | grep 'xdebug.ini'
/etc/php/8.5/cli/conf.d/20-xdebug.ini,
Now amend your xdebug.ini to have this and remember to use your ip
zend_extension=xdebug.so
xdebug.mode = develop,debug
#xdebug.start_with_request = trigger
xdebug.start_with_request = yes
xdebug.client_port = 9003
xdebug.client_host = 172.28.58.213
Set up VS Code
Install extension Php Debug by Xdebug and create a launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "Listen for Xdebug",
"type": "php",
"request": "launch",
"port": 9003
}
]
}
Note the robot wanted me to put this in the launch.json file and it stopped it working
"pathMappings": {
"/": "${workspaceFolder}"
}
Running in VS Code
For me I simply pressed F5 to run the launch.json and ran the code with
php -S localhost:1701
You need to go to you browser and access you php application. Mine starts with index.php to http://localhost:1701. You must press F5 before starting code because the code needs to find the debugger when starting. For me I saw this when working
[Thu Mar 12 13:29:40 2026] PHP 8.5.3 Development Server (http://localhost:1701) started
[Thu Mar 12 13:29:47 2026] 127.0.0.1:37794 Accepted
[Thu Mar 12 13:29:47 2026] 127.0.0.1:37794 [200]: GET /
[Thu Mar 12 13:29:47 2026] 127.0.0.1:37794 Closing
[Thu Mar 12 13:29:47 2026] 127.0.0.1:37808 Accepted
And this when failed
[Thu Mar 12 13:26:38 2026] PHP 8.5.3 Development Server (http://localhost:1701) started
[Thu Mar 12 13:26:51 2026] 127.0.0.1:39096 Accepted
[Thu Mar 12 13:26:51 2026] Xdebug: [Step Debug] Could not connect to debugging client. Tried: 172.28.58.213:9003 (through xdebug.client_host/xdebug.client_port).
[Thu Mar 12 13:26:51 2026] 127.0.0.1:39096 [200]: GET /
[Thu Mar 12 13:26:51 2026] 127.0.0.1:39096 Closing
[Thu Mar 12 13:26:51 2026] 127.0.0.1:39106 Accepted
Other Stuff I installed
We need to install
sudo apt install php-cli composer php-xml
You will need to set up php-cs-fixer first. Extensions suggested are
- PHP Intelephense
- PHP Getters & Setters
- PHP debug
- PHP CS Fixer
- Twig Language 2
- SQLTools
Creating Project With Composer
To create a project you need to run the following. The only tricky bit is the name where they want vendor/name e.g. bibble/test
composer init
Revisit 2026
Introduction
So not been serious about PHP ever. Done some with eServ, the PMI webpage, Wifey's wordpress and some work in Matakina but in general, did what I needed to do and got out as fast as possible.
Composer
This as the first time I have used composer knowingly. This appears to be like npm and looking at the example below we can see
- Dependencies
- Scripts
- Project Properties
{
"name": "bibble/wp-bibble-calendar",
"description": "A modular PHP calendar project",
"require": {
"php": "^8.1"
},
"require-dev": {
"captainhook/captainhook": "^5.28",
"friendsofphp/php-cs-fixer": "^3.94",
"phpstan/phpstan": "^2.1",
"squizlabs/php_codesniffer": "^4.0",
"symplify/phpstan-rules": "^14.9"
},
"autoload": {
"psr-4": {
"Core\\": "src/Core/",
"Components\\": "src/Components/",
"App\\": "src/App/"
}
},
"scripts": {
"phpstan": "phpstan analyse",
"php-cs": "php-cs-fixer fix --allow-risky=yes --sequential",
"php-cs-check": "php-cs-fixer fix --dry-run --diff --sequential",
"lint": "phpcs --colors --standard=phpcs.xml src index.php",
"lint-fix": "phpcbf --standard=phpcs.xml src index.php"
}
}
Below is more on autoload
Autoload
In the old days I use to do this which is now probably a very very old approach.
require_once __DIR__ . '/../../../constants/days.php';
The autoload section works out what is required and autoloads it. In my case I have the directories under the src directories. You need to initialize and refresh this by running
composer dump-autoload
There are rules around it but none I will remember. I think basically if you change composer.json.
Scripts
So you can see I use scripts these are much the same as npm. The real part is on the right
- phpstan - Is a static analysis tool.
- php-cs - Checks code for violations
- phpcbf - Fixes issues php-cs reports
I set these up in https://git.bibble.co.nz/bibble235/wp-bibble-calendar hopefully using best practice. Like most of these tools, it probably helps to know what good looks like.
Captainhook
This is a tool to enable running of the above scripts prior to checking in. Found it a pain to set up but that is the thing with stuff you know nothing about and an out of day robot. Had to read stuff.
Namespaces
So like C# we have namespace and I have taken the same approach. So Core/Domain/Constants/Days.php has the following
<?php
declare(strict_types=1);
namespace Core\Domain\Constants;
class Days
{
....
}
Using it is almost the same as c# with some exceptions
<?php
declare(strict_types=1);
namespace Components\Pages\MonthView;
use Core\Domain\Constants\Days;
class DayCell
{
...
$weekdayLabel = ($rowIndex === 0)
? '<div class=\'month-view-header-month\'>' . Days::SHORT[$weekday] . '</div>'
: '';
...
}
So here is a summary table of what can be autoloaded
| Thing | Autoloaded? | Why |
|---|---|---|
| Class | Yes | PSR-4 maps class names directly to file paths. |
| Interface | Yes | Same PSR-4 class mapping rules apply. |
| Trait | Yes | Loaded through the same class-based autoload mechanism. |
| Enum | Yes | Treated like classes and resolved via PSR-4. |
| Class constant | Yes | Loaded when the class is autoloaded. |
| File-level constant | No | No mapping exists between constant names and files. |
| Function | No | Functions cannot be resolved via PSR-4; no name→file mapping. |
| Global variable | No | Not part of the autoloading system. |
The things that do not autoload you need to find another approach which I will not go into detail here but an example of loading a function might be declare a use statement (note it needs function after use
<?php
declare(strict_types=1);
use function \blah\utils\foo;
Then manually add it to the compose psr-4 section.
"autoload": {
"psr-4": {
"blah\\": "src/blah/"
},
"files": [
"src/blah/utils/functions.php"
]
}