
Php Project Guide
- 2 installs
- 32 repo stars
- Updated July 10, 2026
- jetbrains/phpstorm-claude-marketplace
php-project-guide skill documents >-.
About
php-project-guide skill documents >-. name: php-project-guide description: >- Covers installation, configuration, and when-to-use guidance from the upstream SKILL.md workflow.
- >-.
- Platform-specific setup patterns for php-project-guide.
- Evidence-backed steps from upstream SKILL.md.
- When-to-use criteria for php-project-guide versus alternatives.
Php Project Guide by the numbers
- 2 all-time installs (skills.sh)
- Ranked #611 of 782 Skill Development skills by installs in the Skillselion catalog
- Data as of Jul 26, 2026 (Skillselion catalog sync)
php-project-guide capabilities & compatibility
- Capabilities
- php project guide quick start · php project guide when to use guidance · php project guide integration patterns
- Use cases
- documentation
- IDEs
- intellij · jetbrains
What php-project-guide says it does
Foundational PHP project knowledge for AI agents. Use when working on a PHP
project, setting up a PHP development environment, understanding PHP project
npx skills add https://github.com/jetbrains/phpstorm-claude-marketplace --skill php-project-guideAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 2 |
|---|---|
| repo stars | ★ 32 |
| Last updated | July 10, 2026 |
| Repository | jetbrains/phpstorm-claude-marketplace ↗ |
How do I use php-project-guide correctly?
>-
Who is it for?
Teams implementing php-project-guide workflows from the catalog.
Skip if: Skip when requirements clearly match a different specialized stack.
When should I use this skill?
User asks about php-project-guide, >-.
What you get
Working php-project-guide setup with validated configuration and next steps.
Files
PHP Project Guide
Foundational knowledge for working effectively on any PHP project in PhpStorm. Provides project detection, coding standards, testing patterns, framework guidance, and MCP tool usage.
Quick Start: First Interaction with a PHP Project
Run these steps when encountering a new PHP project for the first time.
1. Detect PHP environment
get_php_project_config()Returns the configured PHP language level, interpreter details (name, path, local/remote), and runtime information (exact PHP version, loaded extensions, php.ini path, debuggers). Use this to understand the PHP environment before generating code.
2. Identify dependencies and framework
get_composer_dependencies()This returns all installed packages with exact versions from composer.lock. Use it to determine:
- Framework:
laravel/framework,symfony/framework-bundle, or neither - Test framework:
phpunit/phpunit,pestphp/pest,codeception/codeception - Static analysis:
phpstan/phpstan,vimeo/psalm - Code style:
friendsofphp/php-cs-fixer,squizlabs/php_codesniffer
Use the optional nameFilter glob parameter to search for specific packages (e.g., nameFilter: "laravel/*").
3. Route to framework-specific guidance
| Dependency | Project Type | Reference |
|---|---|---|
laravel/framework | Laravel | See references/framework-laravel.md |
symfony/framework-bundle | Symfony | See references/framework-symfony.md |
| Neither | Generic PHP | See references/php-standards.md |
PhpStorm MCP Tools Quick Reference
Code Analysis
| Tool | When to Use |
|---|---|
get_inspections | After edits, for code review, to find problems with available quick fixes |
apply_quick_fix | To resolve inspection problems automatically |
get_file_problems | Quick error/warning check on any file type (no quick fixes returned) |
build_project | Trigger project build and get compilation errors |
Code Search
| Tool | When to Use |
|---|---|
search_structural | To find code patterns semantically using SSR (requires fileType: "PHP") |
get_structural_patterns | To discover predefined PHP search patterns by category |
search_text | Fast text substring search across project files |
search_regex | Regex search across project files with match coordinates |
search_symbol | Semantic symbol lookup (classes, methods, fields) |
search_file | Find files by glob pattern |
find_files_by_name_keyword | Fast file search by name substring (uses indexes) |
find_files_by_glob | Find files matching glob pattern recursively |
Code Intelligence
| Tool | When to Use |
|---|---|
get_symbol_info | Get Quick Documentation for a symbol at a specific position |
rename_refactoring | Safely rename a symbol across the entire project |
get_php_project_config | Get PHP language level, interpreter, extensions, runtime info |
get_composer_dependencies | Understand project dependencies, framework, and versions |
File Operations
| Tool | When to Use |
|---|---|
read_file | Read file with advanced modes (slice, lines, offsets, indentation) |
get_file_text_by_path | Read full file text by project-relative path |
replace_text_in_file | Targeted find-and-replace in files |
create_new_file | Create new files with content |
reformat_file | Apply IDE code formatting rules |
Execution
| Tool | When to Use |
|---|---|
get_run_configurations | List available run/test configurations |
execute_run_configuration | Run a specific configuration and get results |
execute_terminal_command | Run shell commands in IDE terminal |
See references/mcp-tools-reference.md for detailed parameters and usage patterns.
Documentation Lookup
When you need documentation beyond what these references provide:
- Context7 MCP: Use
resolve-library-idthenquery-docsfor any PHP framework or library — returns up-to-date docs and code examples - PHP official docs: https://www.php.net/manual
- PhpStorm help: https://www.jetbrains.com/help/phpstorm/
- phpstorm-stubs: https://github.com/JetBrains/phpstorm-stubs — PHP built-in function signatures and type info
Reference Documents
| Reference | Content |
|---|---|
references/project-detection.md | composer.json anatomy, PSR-4 autoloading, directory layouts |
references/php-standards.md | PER/PSR coding standards, PHP version features, anti-patterns |
references/testing-guide.md | PHPUnit, Pest, running tests, common mistakes |
references/framework-laravel.md | Laravel directory structure, Eloquent, artisan, routes |
references/framework-symfony.md | Symfony directory structure, Doctrine, console, services |
references/static-analysis.md | PHPStan, Psalm, PHP CS Fixer, PHP CodeSniffer |
references/composer-guide.md | Composer commands, version constraints, autoloading |
references/mcp-tools-reference.md | Detailed PhpStorm MCP tool parameters and workflows |
Composer Dependency Management
Core Files
| File | Purpose | Commit? |
|---|---|---|
composer.json | Declares dependencies and version constraints | Yes |
composer.lock | Locks exact versions for reproducible installs | Yes (for applications), No (for libraries) |
vendor/ | Installed packages | No (gitignored) |
Common Commands
| Command | Purpose |
|---|---|
composer install | Install exact versions from composer.lock |
composer update | Update dependencies to newest versions matching constraints, regenerates composer.lock |
composer require package/name | Add a production dependency |
composer require --dev package/name | Add a development dependency |
composer remove package/name | Remove a dependency |
composer dump-autoload | Regenerate autoloader (needed after adding files to classmap) |
composer dump-autoload --optimize | Optimize autoloader for production |
composer audit | Check dependencies for known security vulnerabilities |
composer outdated | List packages with newer versions available |
composer show package/name | Show details about a specific package |
install vs update
- `composer install`: Reads
composer.lockand installs those exact versions. Use in CI/CD and deployment. If no lock file exists, behaves likeupdate. - `composer update`: Resolves constraints in
composer.json, finds newest matching versions, updatescomposer.lock. Use during development when you want newer versions.
Version Constraints
| Syntax | Meaning | Example |
|---|---|---|
^1.2 | >=1.2.0 <2.0.0 (next major) | Most common — allows minor and patch updates |
~1.2 | >=1.2.0 <2.0.0 (last digit goes up) | ~1.2.3 = >=1.2.3 <1.3.0 (more restrictive) |
>=1.2 | >=1.2.0 (no upper bound) | Dangerous — may break on major updates |
1.2.* | >=1.2.0 <1.3.0 | Wildcard on patch version only |
1.2.3 | Exact version | Avoid unless necessary |
Recommendation: Use ^ (caret) for most dependencies. It follows semantic versioning and allows safe updates.
Autoloading
When dump-autoload Is Needed
- After adding a new PSR-4 root in
composer.json - After adding files to
classmaporfilesautoload sections - After manually placing files outside PSR-4 conventions
- Not needed after creating new classes within existing PSR-4 namespaces (the autoloader resolves these dynamically)
Autoload Types
| Type | Use Case |
|---|---|
psr-4 | Standard namespace-to-directory mapping (most common) |
psr-0 | Legacy namespace mapping (deprecated, avoid in new projects) |
classmap | Scan directories and build a class-to-file map |
files | Always load these files (for helper functions) |
Using get_composer_dependencies
The get_composer_dependencies MCP tool returns all Composer packages installed in the project with their exact versions. It reads from already-indexed composer.lock data — no disk I/O or network calls. In monorepo setups, packages from all composer.json sub-projects are included.
Use the optional nameFilter glob parameter to search for specific packages:
nameFilter: "laravel/*"— find all Laravel packagesnameFilter: "*phpunit*"— find PHPUnit-related packagesnameFilter: "symfony/console"— find a specific package
Use this to:
- Detect which framework is installed
- Check if a specific library is available before suggesting its use
- Verify package versions for compatibility
Security
Run composer audit to check for known vulnerabilities in dependencies. This checks against the PHP Security Advisories Database.
Monorepo Considerations
In monorepo setups, get_composer_dependencies includes packages from all composer.json sub-projects:
- Each sub-project has its own dependency tree
- Sub-projects may have different PHP version requirements
- Use the
composer.jsonclosest to the file being edited
External References
- Composer docs: https://getcomposer.org/doc/
- Packagist (package registry): https://packagist.org/
- Version constraints: https://getcomposer.org/doc/articles/versions.md
- Composer security advisories: https://github.com/FriendsOfPHP/security-advisories
Laravel Framework Guide
Directory Structure Quick Reference
| Directory | Purpose |
|---|---|
app/Models/ | Eloquent model classes (singular naming: User, Post) |
app/Http/Controllers/ | Route controllers |
app/Http/Middleware/ | HTTP middleware |
app/Http/Requests/ | Form request validation classes |
app/Providers/ | Service providers |
app/Services/ | Business logic (convention, not enforced) |
config/ | Configuration files (e.g., config/database.php) |
database/factories/ | Model factories for testing |
database/migrations/ | Database schema migrations |
database/seeders/ | Database seeders |
resources/views/ | Blade templates (.blade.php) |
routes/web.php | Web routes (session, CSRF) |
routes/api.php | API routes (stateless, token auth) |
tests/Feature/ | Feature/integration tests |
tests/Unit/ | Unit tests |
storage/ | Logs, cache, file uploads |
Key Concepts
Eloquent Models
- Located in
app/Models/by convention - Class name is singular (
User), table name is plural (users) by default - `$fillable`: Whitelist of mass-assignable attributes
- `$guarded`: Blacklist of non-mass-assignable attributes
- `$casts`: Attribute type casting (e.g.,
'email_verified_at' => 'datetime')
Before writing any Eloquent code, verify the actual schema by reading migration files or using php artisan model:show.
Migrations
Located in database/migrations/. File names include timestamps for ordering:
2024_01_15_000000_create_users_table.phpRead migration files to understand the actual database schema when php artisan model:show is not available.
Routes
| File | Middleware | Use Case |
|---|---|---|
routes/web.php | web (session, CSRF, cookies) | Browser-facing pages |
routes/api.php | api (stateless, rate limiting) | API endpoints |
routes/console.php | None | Artisan command definitions |
Route model binding: Route::get('/users/{user}', ...) automatically resolves {user} to a User model instance.
Controllers
- Located in
app/Http/Controllers/ - Resource controllers provide CRUD methods:
index,create,store,show,edit,update,destroy - Invocable controllers have a single
__invoke()method
Form Requests
- Located in
app/Http/Requests/ - Encapsulate validation rules and authorization logic
- Method
rules()returns validation rules array - Method
authorize()returns boolean for authorization
Blade Templates
- Located in
resources/views/ - Use
.blade.phpextension - Directives:
@if,@foreach,@extends,@section,@yield,@include,@component - Echo:
{{ $variable }}(escaped),{!! $html !!}(raw)
Service Container and Dependency Injection
- Laravel auto-resolves constructor dependencies via the service container
- Prefer constructor injection over facades for testability
- Facades (e.g.,
Cache::get()) are static proxies to container-resolved instances - Service providers in
app/Providers/register bindings
Essential Artisan Commands
| Command | Purpose |
|---|---|
php artisan model:show Model | Inspect model schema, relationships, attributes |
php artisan route:list | List all registered routes |
php artisan make:model Name -mfc | Generate model + migration + factory + controller |
php artisan make:controller Name | Generate controller |
php artisan make:request Name | Generate form request |
php artisan make:test Name | Generate test (Feature by default) |
php artisan make:test Name --unit | Generate unit test |
php artisan migrate | Run pending migrations |
php artisan migrate:rollback | Roll back last migration batch |
php artisan test | Run test suite |
php artisan tinker | Interactive REPL with app context |
php artisan config:clear | Clear configuration cache |
php artisan cache:clear | Clear application cache |
Structural Search Patterns for Laravel
Use search_structural with fileType: "PHP" to find common Laravel patterns. Pattern variables use $name$ syntax:
| Pattern | What It Finds |
|---|---|
$model$::where($args$) | Eloquent query builders |
Route::get($args$) | GET route definitions |
Route::post($args$) | POST route definitions |
$model$::factory() | Factory usage |
$var$->hasMany($args$) | HasMany relationships |
$var$->belongsTo($args$) | BelongsTo relationships |
Environment Configuration
.env— local environment variables (gitignored, never commit).env.example— template with placeholder values (committed)- Access via
env('KEY')(only in config files) orconfig('app.key')(everywhere else)
External References
- Laravel docs: https://laravel.com/docs/
- Larastan (PHPStan for Laravel): https://github.com/larastan/larastan
- Laravel Pint (code style): https://laravel.com/docs/pint
Symfony Framework Guide
Directory Structure Quick Reference
| Directory | Purpose |
|---|---|
src/ | Application source code (controllers, entities, services) |
src/Controller/ | Route controllers |
src/Entity/ | Doctrine ORM entities |
src/Repository/ | Doctrine repositories |
src/Command/ | Console commands |
src/Form/ | Form types |
src/EventSubscriber/ | Event subscribers |
src/Security/ | Authentication and authorization |
config/ | Application configuration |
config/packages/ | Bundle-specific configuration |
config/routes/ | Routing definitions |
config/services.yaml | Service container configuration |
migrations/ | Doctrine database migrations |
templates/ | Twig templates |
tests/ | Test files |
translations/ | Translation files |
public/ | Web server document root |
var/ | Cache and logs (gitignored) |
Key Concepts
Service Container and Autowiring
Symfony's core is its dependency injection container.
- Autowiring: Services are automatically resolved by type-hinting constructor parameters
- `config/services.yaml`: Configures service registration and argument binding
- Services in
src/are auto-registered by default - Tags: Mark services for specific purposes (e.g.,
kernel.event_subscriber)
Configuration
Symfony supports YAML, PHP, and XML configuration:
config/packages/— per-bundle settings (e.g.,doctrine.yaml,security.yaml)config/services.yaml— service definitions and parametersconfig/routes.yaml— route imports (or use PHP attributes on controllers)config/bundles.php— registered bundles
Doctrine ORM
Symfony's default database layer.
Entities (src/Entity/):
- Annotated PHP classes mapped to database tables
- Use
#[ORM\Entity],#[ORM\Column],#[ORM\Id]attributes - Naming: entity
Usermaps to tableuserby default
Repositories (src/Repository/):
- Custom query methods extending
ServiceEntityRepository - Injected via autowiring: type-hint
UserRepositoryin constructors
Migrations (migrations/):
- Generated with
php bin/console make:migration - Applied with
php bin/console doctrine:migrations:migrate
Routing
Two main styles:
PHP Attributes (preferred):
#[Route('/users/{id}', name: 'user_show', methods: ['GET'])]
public function show(User $user): Response { ... }YAML (config/routes.yaml):
user_show:
path: /users/{id}
controller: App\Controller\UserController::show
methods: [GET]Twig Templates
- Located in
templates/ - Extension:
.html.twig - Syntax:
{{ variable }}for output,{% block %}for structure,{# comment #} - Inheritance:
{% extends 'base.html.twig' %}with{% block content %}...{% endblock %}
Console Commands
- Located in
src/Command/ - Extend
Symfony\Component\Console\Command\Command - Auto-registered via service container
Forms and Validation
- Form types in
src/Form/define field structure - Validation uses
#[Assert\*]attributes on entity properties - Built-in constraints:
NotBlank,Email,Length,Valid,UniqueEntity
Essential CLI Commands
| Command | Purpose |
|---|---|
php bin/console debug:router | List all routes |
php bin/console debug:container | List all services |
php bin/console debug:config BundleName | Show bundle configuration |
php bin/console doctrine:schema:validate | Validate entity mapping vs database |
php bin/console doctrine:migrations:migrate | Run pending migrations |
php bin/console make:controller Name | Generate controller |
php bin/console make:entity Name | Generate Doctrine entity |
php bin/console make:form Name | Generate form type |
php bin/console make:migration | Generate migration from entity changes |
php bin/console make:command Name | Generate console command |
php bin/console cache:clear | Clear application cache |
Testing in Symfony
| Test Type | Base Class | Use Case |
|---|---|---|
| Unit | PHPUnit\Framework\TestCase | Pure logic, no container |
| Integration | KernelTestCase | Tests needing services |
| Functional | WebTestCase | HTTP request/response testing |
// Functional test example
class UserControllerTest extends WebTestCase
{
public function test_user_page_loads(): void
{
$client = static::createClient();
$client->request('GET', '/users');
$this->assertResponseIsSuccessful();
}
}External References
- Symfony docs: https://symfony.com/doc/current/index.html
- Doctrine ORM: https://www.doctrine-project.org/projects/orm.html
- Twig docs: https://twig.symfony.com/doc/
- Symfony best practices: https://symfony.com/doc/current/best_practices.html
PhpStorm MCP Tools Reference
Detailed usage guide for MCP tools provided by the PhpStorm JetBrains IDE plugin.
get_inspections
Analyze a file using the IDE's inspections. Returns problems with severity, description, location, and available quick fixes.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
filePath | string | (required) | Path to file, relative to project root |
minSeverity | string | "WEAK_WARNING" | Minimum severity: ERROR, WARNING, WEAK_WARNING, INFORMATION |
timeout | int | (IDE default) | Timeout in milliseconds |
Severity Levels
| Severity | Typical Issues |
|---|---|
ERROR | Syntax errors, unresolved symbols, type mismatches |
WARNING | Potential bugs, missing overrides |
WEAK_WARNING | Code style, best practices, missing type hints |
INFORMATION | Suggestions, hints |
Note: Most PHP inspections report at WEAK_WARNING level. Use WEAK_WARNING as the default to capture most issues. Use ERROR when you only want critical problems.
Response Format
Each problem includes:
severity:ERROR,WARNING,WEAK_WARNING, orINFORMATIONline,column: 1-based locationdescription: Human-readable problem descriptionquickFixes: Array of available automated fixes (each withname)
Difference from get_file_problems
| Feature | get_inspections | get_file_problems |
|---|---|---|
| Quick fixes | Included with name | Not included |
| Filtering | By minimum severity | By errorsOnly flag |
| Use when | Need quick fixes or fine-grained severity control | Quick error check on any file type |
apply_quick_fix
Apply an automated fix for a specific inspection problem.
Parameters
| Parameter | Type | Description |
|---|---|---|
filePath | string | Path to file, relative to project root |
line | int | 1-based line number from inspection result |
column | int | 1-based column number from inspection result |
quickFixName | string | Exact name from the quickFixes array |
Workflow
1. Always run `get_inspections` first — you need the exact line, column, and quickFixName values 2. Match `quickFixName` exactly — use the name string as returned by inspections 3. Re-run inspections after applying — verify the fix took effect and didn't introduce new issues
Example
# Step 1: Find problems
get_inspections(filePath: "app/Services/UserService.php", minSeverity: "WARNING")
# Returns: line=15, column=9,
# quickFixes=[{name: "Safe delete '$temp'"}]
# Step 2: Apply fix
apply_quick_fix(
filePath: "app/Services/UserService.php",
line: 15, column: 9,
quickFixName: "Safe delete '$temp'"
)
# Step 3: Verify
get_inspections(filePath: "app/Services/UserService.php", minSeverity: "WARNING")search_structural
Search for code patterns using Structural Search and Replace (SSR). Unlike text/regex search, SSR understands code structure semantically.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
pattern | string | (required) | SSR pattern to search for |
fileType | string | (required) | Language: "PHP", "Java", "Kotlin", "Python" |
directoryToSearch | string | (project root) | Directory scope, relative to project root |
constraints | object | (none) | Variable constraints (see below) |
maxResults | int | 100 | Maximum number of results to return |
timeout | int | (IDE default) | Timeout in milliseconds |
Pattern Syntax
Use $name$ for template variables that match any expression:
| Pattern | Matches |
|---|---|
$a$->$b$() | Any method call on any object |
$a$->$b$ | Any property access on any object |
new $Class$() | Any object instantiation |
class $a$ extends $b$ {} | Any class that extends another |
$a$::$b$() | Any static method call |
$a$ = $b$ | Any assignment |
Count modifiers (in pattern):
$a${2,5}— matches 2 to 5 occurrences$a$+— one or more occurrences$a$*— zero or more occurrences
Constraints
Constraints refine what template variables can match. Use the variable name without dollar signs as the key:
{
"a": {
"regex": "User.*",
"exprType": "App\\Models\\User"
},
"b": {
"minCount": 1,
"maxCount": 5
}
}| Constraint | Purpose |
|---|---|
regex | Variable text must match this regex |
invertRegex | Invert the regex match |
exprType | Expression must be of this PHP type |
invertExprType | Invert the expression type match |
minCount | Minimum number of occurrences |
maxCount | Maximum number of occurrences |
wholeWordsOnly | Match whole words only |
withinHierarchy | Include type hierarchy in matching |
Practical Examples
# Find all Eloquent where() calls
search_structural(pattern: "$model$::where($args$)", fileType: "PHP")
# Find all class definitions extending Model
search_structural(pattern: "class $name$ extends Model {}", fileType: "PHP")
# Find all route definitions in routes directory
search_structural(
pattern: "Route::$method$($args$)",
fileType: "PHP",
directoryToSearch: "routes"
)
# Find try-catch blocks with empty catch
search_structural(pattern: "try { $body$ } catch ($e$) { }", fileType: "PHP")
# Find method calls matching a regex on the method name
search_structural(
pattern: "$a$->$b$()",
fileType: "PHP",
constraints: {"b": {"regex": "^get.*"}}
)Known Limitations
- Some class modifiers (e.g.,
readonly) may not be matched - Complex nested patterns with constraints may not work as expected
- Use
get_structural_patternsto discover reliably working patterns
get_structural_patterns
List predefined PHP structural search patterns organized by category.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
category | string | (all) | Filter by category: "General", "Expressions", "Suspicious" |
Response
Returns categories of patterns with descriptions:
- General: Class, interface, trait definitions and structure
- Expressions: Assignments, method calls, field access, etc.
- Suspicious: Potentially problematic code patterns
Use these predefined patterns as templates — modify them for your specific search needs.
get_composer_dependencies
Return all Composer packages installed in the project with their exact versions. Reads from already-indexed composer.lock data — no disk I/O or network calls.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
nameFilter | string | (all) | Glob pattern to filter packages (e.g., "laravel/*", "*phpunit*", "symfony/console"). Case-insensitive. |
Use Cases
| Use Case | How |
|---|---|
| Detect framework | Filter with nameFilter: "laravel/*" or check for symfony/framework-bundle |
| Check library availability | Search packages by name before suggesting usage |
| Verify versions | Check if a package version supports a feature |
| Find test framework | Filter with nameFilter: "*phpunit*" or "*pest*" |
Example
get_composer_dependencies(nameFilter: "laravel/*")
# Returns packages matching the filter with exact versionsget_php_project_config
Return the PHP project configuration as seen by PhpStorm.
Parameters
None required.
Response
Includes:
- PHP language level: The configured target PHP version (may differ from system PHP)
- Interpreter details: Name, path, local/remote
- PHP runtime information: Exact version, loaded extensions, php.ini path, debuggers
Use Cases
- Determine the project's target PHP version before generating code
- Check if specific PHP extensions are available
- Understand if the interpreter is local or remote (Docker/SSH)
get_symbol_info
Retrieve information about a symbol at a specific position in a file. Provides the same information as PhpStorm's Quick Documentation feature.
Parameters
| Parameter | Type | Description |
|---|---|---|
filePath | string | Path relative to project root |
line | int | 1-based line number |
column | int | 1-based column number |
Response
Returns symbol information including name, signature, type, documentation, and declaration code when available.
Use Cases
- Understand what a function/method does without reading the full source
- Check parameter types and return types
- Find where a symbol is declared
- Get PHPDoc documentation for a class or method
rename_refactoring
Rename a symbol (variable, function, class, etc.) across the entire project. Unlike text search-and-replace, this understands code structure and updates all references safely.
Parameters
| Parameter | Type | Description |
|---|---|---|
pathInProject | string | Path to file containing the symbol, relative to project root |
symbolName | string | Exact current name of the symbol |
newName | string | New name for the symbol |
Use Cases
- Rename a class, method, or variable and update all usages
- Safe refactoring that preserves code integrity
- Always preferred over manual find-and-replace for symbol renaming
get_file_problems
Analyze a file for errors and warnings using IntelliJ's inspections. Lighter than get_inspections — does not return quick fixes.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
filePath | string | (required) | Path relative to project root |
errorsOnly | boolean | false | Only include errors (skip warnings) |
timeout | int | (IDE default) | Timeout in milliseconds |
Search Tools
PhpStorm provides multiple search tools optimized for different use cases:
| Tool | Best For | Key Feature |
|---|---|---|
search_structural | Code patterns (method calls, class definitions) | Semantic understanding of code structure |
search_text | Known text substrings | Fast, with match coordinates |
search_regex | Complex pattern matching | Full regex, with match coordinates |
search_symbol | Finding classes, methods, fields by name | Semantic symbol lookup |
search_file | Finding files by glob pattern | Glob-based file matching |
find_files_by_name_keyword | Finding files by partial name | Fastest — uses IDE indexes |
find_files_by_glob | Finding files by glob in subdirectories | Recursive glob matching |
search_in_files_by_text | Full-project text search with context | Highlights matches with ` |
search_in_files_by_regex | Full-project regex search with context | Highlights matches with ` |
File Operation Tools
| Tool | Description |
|---|---|
read_file | Read file with modes: slice, lines, line_columns, offsets, indentation |
get_file_text_by_path | Read full file content by project-relative path |
replace_text_in_file | Find and replace text in a file (supports regex) |
create_new_file | Create a new file with optional content |
reformat_file | Apply IDE code formatting rules to a file |
open_file_in_editor | Open a file in the IDE editor |
Execution Tools
| Tool | Description |
|---|---|
get_run_configurations | List run/test configurations with command details |
execute_run_configuration | Run a configuration and wait for results |
execute_terminal_command | Execute shell command in IDE terminal |
build_project | Trigger project build and get errors/warnings |
PHP Coding Standards and Language Features
Coding Standards
PER Coding Style (Current Standard)
The latest PHP coding standard, superseding PSR-12.
- Reference: https://www.php-fig.org/per/coding-style/
- 4-space indentation (no tabs)
- 120-character soft line length limit
- Unix LF line endings
- Opening brace on the same line for control structures, next line for classes/methods
- One
useimport per line, grouped by type (classes, functions, constants) declare(strict_types=1)as the first statement after<?php
PSR-12 Extended Coding Style
Still widely used in existing projects.
- Reference: https://www.php-fig.org/psr/psr-12/
- Largely compatible with PER; PER adds clarifications and updates
PSR-4 Autoloading
- Reference: https://www.php-fig.org/psr/psr-4/
- See
references/project-detection.mdfor detailed mapping rules
All PSR Standards
- Reference: https://www.php-fig.org/psr/
PHP Version Detection
Read the require.php field in composer.json:
"require": {
"php": ">=8.2"
}Also check config.platform.php which may override the effective version for dependency resolution.
Rule: Never use language features newer than the project's minimum PHP version.
Modern PHP Features by Version
Check the project's PHP version before using any of these features.
PHP 8.0
- Named arguments:
htmlspecialchars(string: $s, double_encode: false) - Match expression:
match($status) { 'active' => 1, default => 0 } - Constructor promotion:
public function __construct(private string $name) {} - Union types:
function foo(int|string $value): void - Nullsafe operator:
$user?->getAddress()?->getCity() - `str_contains()`, `str_starts_with()`, `str_ends_with()`
PHP 8.1
- Enums:
enum Status: string { case Active = 'active'; } - Readonly properties:
public readonly string $name - Fibers: low-level concurrency primitive
- Intersection types:
function foo(Countable&Iterator $value): void - `never` return type: for functions that always throw or exit
- First-class callable syntax:
$fn = strlen(...)
PHP 8.2
- Readonly classes:
readonly class Point { ... } - DNF types:
(A&B)|null - `true`, `false`, `null` as standalone types
- Constants in traits
- Deprecated: dynamic properties (use
#[AllowDynamicProperties]to opt in)
PHP 8.3
- Typed class constants:
const string NAME = 'value'; - `json_validate()` function
- `#[Override]` attribute: verify method actually overrides parent
- Dynamic class constant fetch:
$class::{$constName}
PHP 8.4
- Property hooks:
public string $name { get => ...; set => ...; } - Asymmetric visibility:
public private(set) string $name - `new` without wrapping parentheses:
new MyClass()->method()(previously required(new MyClass())->method()) - `array_find()`, `array_any()`, `array_all()` functions
Anti-Patterns to Avoid
| Anti-Pattern | Why | Alternative |
|---|---|---|
@ error suppression | Hides bugs silently | Proper error handling or null checks |
eval() | Security risk, hard to debug | Use proper language constructs |
Missing declare(strict_types=1) | Allows silent type coercion | Add to every PHP file |
| Untyped arrays for structured data | Hard to understand, error-prone | DTOs or value objects |
global keyword | Hidden dependencies | Dependency injection |
extract() | Creates variables from nowhere | Access array keys directly |
Suppressing exceptions with empty catch | Hides failures | Log or rethrow |
External References
- PHP-FIG standards: https://www.php-fig.org/psr/
- PHP version lifecycle: https://www.php.net/supported-versions.php
- PHP RFC process: https://wiki.php.net/rfc
Project Detection and Structure
How to understand the structure of any PHP project by reading its configuration files.
composer.json Anatomy
The composer.json file is the single source of truth for a PHP project's structure.
Key Sections
| Section | Purpose |
|---|---|
require | Production dependencies (including php version constraint) |
require-dev | Development dependencies (test frameworks, static analysis) |
autoload | PSR-4 namespace-to-directory mapping for production code |
autoload-dev | PSR-4 mapping for test code |
scripts | Custom commands (e.g., test, lint, analyse) |
config.platform.php | Override PHP version for dependency resolution |
Example
{
"require": {
"php": ">=8.2",
"laravel/framework": "^11.0"
},
"require-dev": {
"phpunit/phpunit": "^11.0",
"phpstan/phpstan": "^2.0"
},
"autoload": {
"psr-4": {
"App\\": "app/",
"Database\\": "database/"
}
},
"autoload-dev": {
"psr-4": {
"Tests\\": "tests/"
}
},
"scripts": {
"test": "phpunit",
"analyse": "phpstan analyse"
}
}PSR-4 Autoloading
PSR-4 maps namespace prefixes to base directories. Understanding this mapping is critical for placing files in the correct location.
How It Works
Given "App\\": "app/":
- Class
App\Models\User→ fileapp/Models/User.php - Class
App\Http\Controllers\Api\UserController→ fileapp/Http/Controllers/Api/UserController.php
Rules: 1. The namespace prefix (App\) is replaced by the base directory (app/) 2. Each remaining namespace separator becomes a directory separator 3. The class name becomes the file name with .php extension 4. Case matters — App\Models\User must be in app/Models/User.php, not app/models/user.php
Resolving FQCN to File Path
To find the file for a fully qualified class name (FQCN):
1. Read autoload.psr-4 from composer.json 2. Find the longest matching namespace prefix 3. Replace the prefix with the corresponding directory 4. Convert remaining \ to / and append .php
Example with mapping "App\\": "app/":
App\Services\Payment\StripeGateway→app/Services/Payment/StripeGateway.php
Common Mistake
Do not confuse the namespace with the directory. The mapping is not always 1:1 with the folder name:
"Domain\\": "src/Domain/"meansDomain\Order\Order→src/Domain/Order/Order.php(notDomain/Order/Order.php)
Common Directory Layouts
Laravel
project-root/
├── app/
│ ├── Console/ # Artisan commands
│ ├── Events/ # Event classes
│ ├── Exceptions/ # Exception handlers
│ ├── Http/
│ │ ├── Controllers/ # Route controllers
│ │ ├── Middleware/ # HTTP middleware
│ │ └── Requests/ # Form request validation
│ ├── Jobs/ # Queue jobs
│ ├── Listeners/ # Event listeners
│ ├── Mail/ # Mailables
│ ├── Models/ # Eloquent models
│ ├── Notifications/ # Notifications
│ ├── Policies/ # Authorization policies
│ ├── Providers/ # Service providers
│ └── Services/ # Business logic (convention)
├── bootstrap/ # Framework bootstrapping
├── config/ # Configuration files
├── database/
│ ├── factories/ # Model factories for testing
│ ├── migrations/ # Database migrations
│ └── seeders/ # Database seeders
├── public/ # Web server document root
├── resources/
│ ├── css/ # Stylesheets
│ ├── js/ # JavaScript
│ └── views/ # Blade templates
├── routes/
│ ├── api.php # API routes
│ ├── console.php # Console routes
│ └── web.php # Web routes
├── storage/ # Logs, cache, uploads
├── tests/
│ ├── Feature/ # Feature/integration tests
│ └── Unit/ # Unit tests
├── .env.example # Environment template
├── artisan # CLI entry point
├── composer.json
└── phpunit.xml(.dist)Symfony
project-root/
├── bin/
│ └── console # CLI entry point
├── config/
│ ├── packages/ # Bundle configuration
│ ├── routes/ # Routing configuration
│ ├── bundles.php # Registered bundles
│ ├── routes.yaml # Main route config
│ └── services.yaml # Service container config
├── migrations/ # Doctrine migrations
├── public/
│ └── index.php # Web entry point
├── src/
│ ├── Command/ # Console commands
│ ├── Controller/ # Route controllers
│ ├── Entity/ # Doctrine entities
│ ├── EventSubscriber/ # Event subscribers
│ ├── Form/ # Form types
│ ├── Repository/ # Doctrine repositories
│ ├── Security/ # Authentication/authorization
│ └── Service/ # Business logic
├── templates/ # Twig templates
├── tests/ # Test files
├── translations/ # Translation files
├── var/ # Cache, logs (gitignored)
├── vendor/ # Dependencies (gitignored)
├── .env # Environment variables
├── composer.json
└── phpunit.xml.distGeneric PHP (No Framework)
project-root/
├── src/ # Application source code
├── tests/ # Test files
├── public/ # Web document root (if applicable)
├── vendor/ # Dependencies (gitignored)
├── composer.json
└── phpunit.xml(.dist)Config Files and Their Meaning
| File | Indicates |
|---|---|
phpunit.xml or phpunit.xml.dist | PHPUnit test configuration |
phpstan.neon or phpstan.neon.dist | PHPStan static analysis config |
psalm.xml | Psalm static analysis config |
.php-cs-fixer.php or .php-cs-fixer.dist.php | PHP CS Fixer code style config |
phpcs.xml or phpcs.xml.dist | PHP CodeSniffer code style config |
.env | Environment variables — never commit this file |
.env.example | Template for environment variables — safe to commit |
rector.php | Rector automated refactoring config |
pint.json | Laravel Pint code style config |
Monorepo Detection
In monorepo setups, get_composer_dependencies includes packages from all composer.json sub-projects. If you find packages from different frameworks or conflicting versions, the project is likely a monorepo. Each composer.json represents a sub-project with its own dependencies and autoloading.
When working in a monorepo: 1. Identify which sub-project the target file belongs to 2. Use that sub-project's composer.json for autoloading resolution 3. Be aware that sub-projects may have different PHP version requirements
Static Analysis Tools
PHPStan
Detection
Config files: phpstan.neon, phpstan.neon.dist, or phpstan.neon.local Package: phpstan/phpstan in require-dev
Levels
PHPStan uses levels 0-9, each adding more checks:
| Level | What It Checks |
|---|---|
| 0 | Basic checks: unknown classes, functions, methods |
| 1 | Possibly undefined variables, unknown magic methods |
| 2 | Unknown methods on all expressions (not just $this), validate PHPDocs |
| 3 | Return types, types assigned to properties |
| 4 | Dead code, unreachable branches |
| 5 | Argument types passed to methods |
| 6 | Missing typehints |
| 7 | Union type handling |
| 8 | Nullable types, method calls on nullable |
| 9 | Mixed type usage (strictest) |
Running
./vendor/bin/phpstan analyse # Analyse with config defaults
./vendor/bin/phpstan analyse src/ # Analyse specific directory
./vendor/bin/phpstan analyse --level=6 # Override levelBaseline
Legacy projects use a baseline file to ignore existing errors:
includes:
- phpstan-baseline.neonThe baseline captures existing errors so new code is held to a higher standard. Regenerate with ./vendor/bin/phpstan --generate-baseline.
Framework Extensions
| Package | Framework |
|---|---|
larastan/larastan | Laravel (model types, collection methods, facades) |
phpstan/phpstan-symfony | Symfony (container types, form types) |
phpstan/phpstan-doctrine | Doctrine (entity types, repository methods) |
phpstan/phpstan-phpunit | PHPUnit (assertion types) |
Psalm
Detection
Config file: psalm.xml or psalm.xml.dist Package: vimeo/psalm in require-dev
Error Levels
Psalm uses levels 1-8 (1 = strictest, 8 = most permissive — opposite to PHPStan).
Running
./vendor/bin/psalm # Analyse with config defaults
./vendor/bin/psalm src/ # Analyse specific directory
./vendor/bin/psalm --show-info # Include informational issuesBaseline
Similar to PHPStan: ./vendor/bin/psalm --set-baseline=psalm-baseline.xml
PHP CS Fixer
Detection
Config files: .php-cs-fixer.php, .php-cs-fixer.dist.php Package: friendsofphp/php-cs-fixer in require-dev
Running
./vendor/bin/php-cs-fixer fix # Fix all files
./vendor/bin/php-cs-fixer fix src/ # Fix specific directory
./vendor/bin/php-cs-fixer fix --dry-run # Preview changes without applying
./vendor/bin/php-cs-fixer fix --diff # Show diff of changesPHP CodeSniffer
Detection
Config files: phpcs.xml, phpcs.xml.dist, .phpcs.xml Package: squizlabs/php_codesniffer in require-dev
Running
./vendor/bin/phpcs # Check code style
./vendor/bin/phpcbf # Auto-fix code style issues
./vendor/bin/phpcs src/ # Check specific directoryLaravel Pint
Detection
Config file: pint.json Package: laravel/pint in require-dev (included by default in Laravel projects)
Running
./vendor/bin/pint # Fix all files
./vendor/bin/pint --test # Preview changes without applyingRelationship to PhpStorm Inspections
PhpStorm's built-in inspections and external static analysis tools may report different issues for the same code. They are complementary:
- PhpStorm inspections (
get_inspections): Real-time, IDE-integrated, includes quick fixes - PHPStan/Psalm: Deeper type analysis, framework-specific rules, CI/CD integration
When both are available, use PhpStorm inspections for quick feedback during editing and external tools for comprehensive analysis.
External References
- PHPStan: https://phpstan.org/user-guide/getting-started
- Psalm: https://psalm.dev/docs/
- PHP CS Fixer: https://cs.symfony.com/
- PHP CodeSniffer: https://github.com/PHPCSStandards/PHP_CodeSniffer
PHP Testing Guide
Detecting the Test Framework
Check require-dev in composer.json or use get_composer_dependencies:
| Package | Framework | Syntax |
|---|---|---|
phpunit/phpunit | PHPUnit | $this->assert*() in classes extending TestCase |
pestphp/pest | Pest | it() / test() closures with expect() chains |
codeception/codeception | Codeception | Step-based $I->... syntax |
behat/behat | Behat | Gherkin .feature files with PHP step definitions |
Most projects use PHPUnit or Pest. Pest is built on PHPUnit — any PHPUnit assertion works inside Pest tests too.
PHPUnit Patterns
Test Class Structure
<?php
declare(strict_types=1);
namespace Tests\Unit;
use PHPUnit\Framework\TestCase;
class CalculatorTest extends TestCase
{
public function test_adds_two_numbers(): void
{
$calculator = new Calculator();
$this->assertEquals(4, $calculator->add(2, 2));
}
}Conventions:
- File naming:
*Test.php(e.g.,CalculatorTest.php) - Class naming:
*TestextendingTestCase - Method naming:
test_*prefix or@testannotation /#[Test]attribute - One test class per file
Important: Base Class Selection
| Project Type | Base Class | Why |
|---|---|---|
| Generic PHP | PHPUnit\Framework\TestCase | No framework container needed |
| Laravel | Tests\TestCase | Boots the Laravel application container |
| Symfony | Symfony\Bundle\FrameworkBundle\Test\KernelTestCase or WebTestCase | Boots the Symfony kernel |
Common mistake: Using PHPUnit\Framework\TestCase in a Laravel feature test — this skips the app container and causes Target class [X] does not exist errors.
Common Assertions
| Assertion | Purpose |
|---|---|
assertEquals($expected, $actual) | Equality with type coercion |
assertSame($expected, $actual) | Strict equality (type + value) |
assertTrue($condition) | Boolean true |
assertFalse($condition) | Boolean false |
assertNull($value) | Null check |
assertCount($expected, $array) | Array/collection count |
assertInstanceOf(Class::class, $obj) | Type check |
assertStringContainsString($needle, $haystack) | Substring check |
assertArrayHasKey($key, $array) | Array key existence |
Data Providers
Supply multiple test cases to a single test method:
#[DataProvider('additionProvider')]
public function test_addition(int $a, int $b, int $expected): void
{
$this->assertEquals($expected, $a + $b);
}
public static function additionProvider(): array
{
return [
'positive numbers' => [1, 2, 3],
'negative numbers' => [-1, -2, -3],
'zero' => [0, 0, 0],
];
}Note: Use #[DataProvider] attribute (PHP 8+) or @dataProvider annotation. The provider method must be static in PHPUnit 10+.
Mocking
$mock = $this->createMock(PaymentGateway::class);
$mock->expects($this->once())
->method('charge')
->with(100, 'USD')
->willReturn(true);
$service = new OrderService($mock);
$result = $service->processPayment(100, 'USD');
$this->assertTrue($result);Key mocking methods:
createMock(Class::class)— creates mock with all methods stubbed (returnsnull)createStub(Class::class)— likecreateMockbut does not verify expectationsexpects($this->once())— verify call countwillReturn($value)— set return valuewillThrowException(new \Exception())— simulate errors
Pest Patterns
Test Structure
<?php
use App\Models\User;
it('can create a user', function () {
$user = User::factory()->create();
expect($user)->toBeInstanceOf(User::class);
});
test('user has a name', function () {
$user = User::factory()->create(['name' => 'John']);
expect($user->name)->toBe('John');
});`it()` vs `test()`: Both are identical. Convention: it('does something') reads as a sentence; test('something works') is more descriptive.
Expectation API
expect($value)
->toBe('exact') // assertSame
->toEqual('loose') // assertEquals
->toBeTrue() // assertTrue
->toBeFalse() // assertFalse
->toBeNull() // assertNull
->toHaveCount(3) // assertCount
->toBeInstanceOf(Foo::class)
->toContain('substring')
->toBeEmpty()
->toBeGreaterThan(5)
->toMatchArray(['key' => 'value']);Lifecycle Hooks
beforeEach(function () {
$this->calculator = new Calculator();
});
afterEach(function () {
// cleanup
});Datasets (Data Providers)
it('adds numbers correctly', function (int $a, int $b, int $expected) {
expect($a + $b)->toBe($expected);
})->with([
[1, 2, 3],
[-1, -2, -3],
[0, 0, 0],
]);Running Tests
Commands
| Runner | Command | Single file | Single test |
|---|---|---|---|
| PHPUnit | ./vendor/bin/phpunit | ./vendor/bin/phpunit tests/Unit/FooTest.php | ./vendor/bin/phpunit --filter test_method_name |
| Pest | ./vendor/bin/pest | ./vendor/bin/pest tests/Unit/FooTest.php | ./vendor/bin/pest --filter "test name" |
| Laravel | php artisan test | php artisan test tests/Feature/FooTest.php | php artisan test --filter test_method_name |
Configuration
phpunit.xml(.dist) controls:
- Test suite directories and file patterns
- Environment variables for testing
- Code coverage settings
- Bootstrap file (typically
vendor/autoload.php)
Common Mistakes
| Mistake | Problem | Fix |
|---|---|---|
Wrong TestCase base class | Container not booted | Use framework's TestCase for feature tests |
Missing RefreshDatabase trait | Stale data between tests | Add use RefreshDatabase; for DB tests |
| Hardcoded IDs | Test depends on insertion order | Use factory-created models |
Not using --filter | Running entire suite for one test | --filter test_name for fast feedback |
| Inventing factory states | State [x] not found error | Read the factory file first to check available states |
Static provider not static | PHPUnit 10+ error | Add static keyword to data provider methods |
External References
- PHPUnit docs: https://docs.phpunit.de/
- Pest docs: https://pestphp.com/docs/writing-tests
- PhpStorm test integration: https://www.jetbrains.com/help/phpstorm/php-test-frameworks.html
Related skills
FAQ
What does php-project-guide do?
php-project-guide skill documents >-.
When should I use php-project-guide?
User asks about php-project-guide, >-.
Is this skill safe to install?
Review the Security Audits panel on this page before installing in production.