PhpSmith
PhpStorm-style "Create missing class / enum / interface / trait" quick fixes for PHP, inside VS Code.
Works with Intelephense, DEVSENSE PHP Tools, and phpactor — the diagnostic filter is source-agnostic.
What it does
Your language server flags an undefined symbol:
Undefined type 'OrderStatus'.
Place the caret on the symbol, press Cmd + . (macOS) / Ctrl + . (Windows/Linux), and choose:
Create Enum: OrderStatus
Create Class: OrderStatus
Create Interface: OrderStatus
Create Trait: OrderStatus
PhpSmith will:
- Show a folder-picker dropdown of candidate folders already in your project (ranked: default → conventional match → others), each labelled with its resolved namespace. Pick one or enter a custom path.
- Derive the correct namespace using
composer.json PSR-4 autoload (falls back to settings).
- Create the file with boilerplate (enum/class/interface/trait).
- Open it with the cursor parked inside the body.
- Insert
use App\Enums\OrderStatus; into the calling file (unless it's in the same namespace or already imported).
The symbol kind is inferred from how it's used — OrderStatus::ACTIVE → enum, new OrderStatus() → class, implements OrderStatus → interface, use OrderStatus; inside a class body → trait. All four options stay available if the heuristic is wrong.
Requirements
- VS Code 1.85+
- One of: Intelephense (free tier is enough), DEVSENSE PHP Tools, or phpactor
Settings
| Setting |
Default |
Description |
phpGenerator.baseNamespace |
App |
Fallback root namespace when no PSR-4 mapping matches. |
phpGenerator.paths |
{ enum: "app/Enums", class: "app/Models", … } |
Default folder per symbol kind. |
phpGenerator.autoImport |
true |
Insert use …; in the calling file after creation. |
phpGenerator.openAfterCreate |
true |
Open the new file in the editor. |
phpGenerator.promptForFolder |
true |
Show the folder-picker dropdown. Set to false to silently use the default. |
phpGenerator.enumBackingType |
string |
string, int, or none (pure enum). |
phpGenerator.addStrictTypes |
false |
Emit declare(strict_types=1);. |
How namespace resolution works
- Read
autoload.psr-4 and autoload-dev.psr-4 from composer.json.
- Sort mappings longest-folder-first so nested mappings win over broader ones.
- For the chosen target folder, pick the mapping whose folder owns that path.
- Append sub-folders to the namespace prefix, converted to PascalCase.
- If no mapping matches, fall back to
phpGenerator.baseNamespace + derived suffix.
Example — standard Laravel composer.json:
{
"autoload": {
"psr-4": { "App\\": "app/" }
}
}
Target folder app/Enums → namespace App\Enums → file app/Enums/OrderStatus.php.
Per-project tweaks
If your project uses singular folder names (e.g. app/Enum instead of app/Enums), pin them in .vscode/settings.json:
{
"phpGenerator.paths": {
"enum": "app/Enum",
"class": "app/Models",
"interface": "app/Contracts",
"trait": "app/Traits"
}
}
The folder picker will still surface every existing folder in the project — settings only change which one is marked [default].
Development
npm install
npm run compile
Press F5 in VS Code to launch an Extension Development Host with PhpSmith loaded. Reload (Cmd+R / Ctrl+R) after edits.
Build a distributable .vsix:
npx @vscode/vsce package
Known limitations
- Does not yet add
case entries for enums based on usage (planned).
- Does not handle short-name collisions via
as aliases — skips the import instead.
- Folder discovery skips
vendor, node_modules, storage, bootstrap, and dotfolders.
Author
Muhammedh Shadir — muhammedhshadir.com
License
Proprietary — All Rights Reserved. See the LICENSE.txt file included with the extension.