Smithery Logo
MCPsSkillsDocsPricing
Login
Smithery Logo

Accelerating the Agent Economy

Resources

DocumentationPrivacy PolicySystem Status

Company

PricingAboutBlog

Connect

© 2026 Smithery. All rights reserved.

    freekmurze

    php-guidelines-from-spatie

    freekmurze/php-guidelines-from-spatie
    Coding
    704
    1 installs

    About

    SKILL.md

    Install

    Install via Skills CLI

    or add to your agent
    • Claude Code
      Claude Code
    • Codex
      Codex
    • OpenClaw
      OpenClaw
    • Cursor
      Cursor
    • Amp
      Amp
    • GitHub Copilot
      GitHub Copilot
    • Gemini CLI
      Gemini CLI
    • Kilo Code
      Kilo Code
    • Junie
      Junie
    • Replit
      Replit
    • Windsurf
      Windsurf
    • Cline
      Cline
    • Continue
      Continue
    • OpenCode
      OpenCode
    • OpenHands
      OpenHands
    • Roo Code
      Roo Code
    • Augment
      Augment
    • Goose
      Goose
    • Trae
      Trae
    • Zencoder
      Zencoder
    • Antigravity
      Antigravity
    ├─
    ├─
    └─

    About

    Describes PHP and Laravel guidelines provided by Spatie. These rules result in more maintainable, and readable code.

    SKILL.md

    Core Laravel Principle

    Follow Laravel conventions first. If Laravel has a documented way to do something, use it. Only deviate when you have a clear justification.

    PHP Standards

    • Follow PSR-1, PSR-2, and PSR-12
    • Use camelCase for non-public-facing strings
    • Use short nullable notation: ?string not string|null
    • Always specify void return types when methods return nothing

    Class Structure

    • Use typed properties, not docblocks:
    • Constructor property promotion when all properties can be promoted:
    • One trait per line:

    Type Declarations & Docblocks

    • Use typed properties over docblocks
    • Specify return types including void
    • Use short nullable syntax: ?Type not Type|null
    • Document iterables with generics:
      /** @return Collection<int, User> */
      public function getUsers(): Collection
      

    Docblock Rules

    • Don't use docblocks for fully type-hinted methods (unless description needed)
    • Always import classnames in docblocks - never use fully qualified names:
      use \Spatie\Url\Url;
      /** @return Url */
      
    • Use one-line docblocks when possible: /** @var string */
    • Most common type should be first in multi-type docblocks:
      /** @var Collection|SomeWeirdVendor\Collection */
      
    • If one parameter needs docblock, add docblocks for all parameters
    • For iterables, always specify key and value types:
      /**
       * @param array<int, MyObject> $myArray
       * @param int $typedArgument 
       */
      function someFunction(array $myArray, int $typedArgument) {}
      
    • Use array shape notation for fixed keys, put each key on it's own line:
      /** @return array{
         first: SomeClass, 
         second: SomeClass
      } */
      

    Control Flow

    • Happy path last: Handle error conditions first, success case last
    • Avoid else: Use early returns instead of nested conditions
    • Separate conditions: Split compound if statements that use && into nested if statements for better readability
    • Always use curly brackets even for single statements
    • Ternary operators: Each part on own line unless very short
    // Happy path last
    if (! $user) {
        return null;
    }
    
    if (! $user->isActive()) {
        return null;
    }
    
    // Process active user...
    
    // Short ternary
    $name = $isFoo ? 'foo' : 'bar';
    
    // Multi-line ternary
    $result = $object instanceof Model ?
        $object->name :
        'A default value';
    
    // Ternary instead of else
    $condition
        ? $this->doSomething()
        : $this->doSomethingElse();
    
    // Bad: compound condition with &&
    if ($user->isActive() && $user->hasPermission('edit')) {
        $user->edit();
    }
    
    // Good: nested ifs
    if ($user->isActive()) {
        if ($user->hasPermission('edit')) {
            $user->edit();
        }
    }
    

    Laravel Conventions

    Routes

    • URLs: kebab-case (/open-source)
    • Route names: camelCase (->name('openSource'))
    • Parameters: camelCase ({userId})
    • Use tuple notation: [Controller::class, 'method']

    Controllers

    • Plural resource names (PostsController)
    • Stick to CRUD methods (index, create, store, show, edit, update, destroy)
    • Extract new controllers for non-CRUD actions

    Configuration

    • Files: kebab-case (pdf-generator.php)
    • Keys: snake_case (chrome_path)
    • Add service configs to config/services.php, don't create new files
    • Use config() helper, avoid env() outside config files

    Artisan Commands

    • Names: kebab-case (delete-old-records)
    • Always provide feedback ($this->comment('All ok!'))
    • Show progress for loops, summary at end
    • Put output BEFORE processing item (easier debugging):
      $items->each(function(Item $item) {
          $this->info("Processing item id `{$item->id}`...");
          $this->processItem($item);
      });
      
      $this->comment("Processed {$items->count()} items.");
      

    Strings & Formatting

    • String interpolation over concatenation:

    Enums

    • Use PascalCase for enum values:

    Comments

    Be very critical about adding comments as they often become outdated and can mislead over time. Code should be self-documenting through descriptive variable and function names.

    Adding comments should never be the first tactic to make code readable.

    Instead of this:

    // Get the failed checks for this site
    $checks = $site->checks()->where('status', 'failed')->get();
    

    Do this:

    $failedChecks = $site->checks()->where('status', 'failed')->get();
    

    Guidelines:

    • Don't add comments that describe what the code does - make the code describe itself
    • Short, readable code doesn't need comments explaining it
    • Use descriptive variable names instead of generic names + comments
    • Only add comments when explaining why something non-obvious is done, not what is being done
    • Never add comments to tests - test names should be descriptive enough

    Whitespace

    • Add blank lines between statements for readability
    • Exception: sequences of equivalent single-line operations
    • No extra empty lines between {} brackets
    • Let code "breathe" - avoid cramped formatting

    Validation

    • Use array notation for multiple rules (easier for custom rule classes):
      public function rules() {
          return [
              'email' => ['required', 'email'],
          ];
      }
      
    • Custom validation rules use snake_case:
      Validator::extend('organisation_type', function ($attribute, $value) {
          return OrganisationType::isValid($value);
      });
      

    Blade Templates

    • Indent with 4 spaces
    • No spaces after control structures:
      @if($condition)
          Something
      @endif
      

    Authorization

    • Policies use camelCase: Gate::define('editPost', ...)
    • Use CRUD words, but view instead of show

    Translations

    • Use __() function over @lang:

    API Routing

    • Use plural resource names: /errors
    • Use kebab-case: /error-occurrences
    • Limit deep nesting for simplicity:
      /error-occurrences/1
      /errors/1/occurrences
      

    Testing

    • Keep test classes in same file when possible
    • Use descriptive test method names
    • Follow the arrange-act-assert pattern

    Quick Reference

    Naming Conventions

    • Classes: PascalCase (UserController, OrderStatus)
    • Methods/Variables: camelCase (getUserName, $firstName)
    • Routes: kebab-case (/open-source, /user-profile)
    • Config files: kebab-case (pdf-generator.php)
    • Config keys: snake_case (chrome_path)
    • Artisan commands: kebab-case (php artisan delete-old-records)

    File Structure

    • Controllers: plural resource name + Controller (PostsController)
    • Views: camelCase (openSource.blade.php)
    • Jobs: action-based (CreateUser, SendEmailNotification)
    • Events: tense-based (UserRegistering, UserRegistered)
    • Listeners: action + Listener suffix (SendInvitationMailListener)
    • Commands: action + Command suffix (PublishScheduledPostsCommand)
    • Mailables: purpose + Mail suffix (AccountActivatedMail)
    • Resources/Transformers: plural + Resource/Transformer (UsersResource)
    • Enums: descriptive name, no prefix (OrderStatus, BookingType)

    Migrations

    • do not write down methods in migrations, only up methods

    Code Quality Reminders

    PHP

    • Use typed properties over docblocks
    • Prefer early returns over nested if/else
    • Use constructor property promotion when all properties can be promoted
    • Avoid else statements when possible
    • Split compound if conditions using && into nested if statements
    • Use string interpolation over concatenation
    • Always use curly braces for control structures
    • Always import namespaces with use statements — never use inline fully qualified class names (e.g. \Exception, \Illuminate\Support\Facades\Http)
    • Never use single-letter variable names — use descriptive names (e.g. $exception not $e, $request not $r)
    Repository
    freekmurze/dotfiles
    Files