Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Phpstan Symfony Laravel Package

phpstan/phpstan-symfony

PHPStan extension for Symfony that improves static analysis with precise return types and framework-specific rules. Understands container/services, parameters, controllers, request/headers, serializer, forms, messenger handlers, cache callbacks, config tree builders, and more.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require --dev phpstan/phpstan-symfony
    

    Use phpstan/extension-installer for automatic inclusion, or manually add to phpstan.neon:

    includes:
        - vendor/phpstan/phpstan-symfony/extension.neon
        - vendor/phpstan/phpstan-symfony/rules.neon
    
  2. Configure Container XML Path: Add this to your phpstan.neon (adjust path for Symfony 4/5/6):

    parameters:
        symfony:
            containerXmlPath: var/cache/dev/App_KernelDevDebugContainer.xml
    
  3. First Use Case: Run PHPStan on your Symfony project:

    vendor/bin/phpstan analyse src --level=max
    

    The extension will now provide accurate type hints for Symfony services, controllers, and dependencies.


Implementation Patterns

1. Service Container Type Safety

  • Automatic Type Inference: Replace get() calls with precise return types:

    $mailer = $container->get(MailerInterface::class); // No `mixed` return
    

    The extension resolves service IDs to their actual classes.

  • Service Existence Checks: Use has() with confidence:

    if ($container->has('app.mailer')) { // Type-safe condition
        $mailer = $container->get('app.mailer');
    }
    

2. Controller and Dependency Injection

  • Constructor Injection: PHPStan validates autowired services:

    public function __construct(
        private MailerInterface $mailer, // Validated as `MailerInterface`
        private LoggerInterface $logger  // Validated as `LoggerInterface`
    ) {}
    
  • Method Injection: Use @required or #[Required] attributes for mandatory services:

    #[Required] private EntityManagerInterface $em;
    

3. Messenger and CQRS

  • Query Bus Typing: Configure HandleTrait wrappers in phpstan.neon:
    parameters:
        symfony:
            messenger:
                handleTraitWrappers:
                    - App\Bus\QueryBus::dispatch
    
    Now dispatch() returns the handler’s result type:
    $product = $queryBus->dispatch(new GetProductQuery()); // Returns `Product`
    

4. Console Commands

  • Argument/Option Validation: Provide a console application loader:
    parameters:
        symfony:
            consoleApplicationLoader: tests/ConsoleApplication.php
    
    PHPStan validates argument/option types:
    $name = $input->getArgument('name'); // Type-checked as `string`
    

5. Forms and Serialization

  • Form Errors: FormInterface::getErrors() returns typed FormErrorInterface[]:
    $errors = $form->getErrors(true, false); // Returns `FormErrorInterface[]`
    
  • Serializer: deserialize() resolves return types from $type:
    $user = $serializer->deserialize($data, User::class, 'json');
    

6. Configuration and Cache

  • TreeBuilder: Type-safe node definitions:
    $builder->root('app', null)
        ->children()
            ->scalarNode('timeout')->defaultValue(30)->end()
        ->end();
    
  • Cache: CacheInterface::get() infers callback return types.

Gotchas and Tips

Pitfalls

  1. Container XML Path:

    • Issue: Missing or incorrect containerXmlPath causes no service type resolution.
    • Fix: Verify the path matches your Symfony version (e.g., App_KernelDevDebugContainer.xml for Symfony 5+).
    • Debug: Run php bin/console debug:container --parameters to confirm the correct path.
  2. Constant Hassers:

    • Issue: has() methods may incorrectly resolve to true/false for optional dependencies.
    • Fix: Disable with:
      parameters:
          symfony:
              constantHassers: false
      
    • Warning: This hides genuine missing-service errors.
  3. Console Application Loader:

    • Issue: PhpParser conflicts if container.dumper.inline_class_loader is true.
    • Fix: Add to config/packages/phpstan_env/parameters.yaml:
      parameters:
          container.dumper.inline_class_loader: false
      
  4. Messenger HandleTrait:

    • Issue: Unconfigured wrappers default to mixed return types.
    • Fix: Explicitly list all wrapper methods in handleTraitWrappers.
  5. Private Services:

    • Issue: Accessing private services (e.g., private app.mailer) triggers warnings.
    • Fix: Use allowPrivateServices: true (not recommended) or refactor to public services.
  6. Dynamic Stub Loading:

    • Issue: Some Symfony classes (e.g., TraceableMessageBus) may lack stubs.
    • Fix: Update the extension or manually add stubs to stubs/.

Debugging Tips

  • Enable Verbose Output: Run PHPStan with --verbose to see which extensions are loaded.
  • Check Coverage: Use --generate-report=html to identify untyped Symfony components.
  • Isolate Issues: Test with a minimal phpstan.neon to isolate configuration problems.

Performance Quirks

  • Lazy Container Parsing: The extension parses container.xml only when needed (since v2.0.17), reducing startup time.
  • Scan Directories: For Symfony 5.3+ with PHP config files, add:
    parameters:
        scanDirectories:
            - var/cache/dev/Symfony/Config
    

Extension Points

  1. Custom Rules: Extend SymfonyExtension to add project-specific checks (e.g., validating custom service aliases).
  2. Stub Files: Override stubs in stubs/ for unsupported Symfony versions or custom bundles.
  3. Messenger Handlers: Add custom handleTraitWrappers for non-standard query buses.

Symfony-Specific Workarounds

  • Optional Dependencies: Use ?ServiceInterface for optional services:
    public function __construct(?MailerInterface $mailer = null) {}
    
  • Legacy Code: Suppress warnings for untyped services with @var:
    /** @var mixed */
    $service = $container->get('legacy_service');
    

Pro Tips

  • Level Up Gradually: Start with --level=5 and incrementally raise to max to avoid overwhelming feedback.
  • CI Integration: Cache the container XML in CI to avoid rebuilds:
    php bin/console cache:clear --env=test --no-warmup
    
  • IDE Synergy: Configure your IDE (PHPStorm/VsCode) to use the same PHPStan config for real-time feedback.

```markdown
## Example Workflow
1. **Daily Use**:
   ```bash
   vendor/bin/phpstan analyse src --level=7 --memory-limit=1G

Fix type errors in controllers/services, then commit.

  1. Pre-Merge: Add --level=max to catch edge cases before PRs.

  2. Onboarding: Run vendor/bin/phpstan analyse --generate-report=html to identify high-priority fixes for new devs.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
calmfox/watch-sylius
damienfern/grpc-symfony-bundle
atoolo/index-bundle
atoolo/genai-bundle
coprotoai/laravel-ticket
davidjln/llm-carbon-bundle
cryonighter/valid-request-bundle
coolms/taxonomy-bundle
coolms/field-bundle
articulate-orm/symfony
aaix/laravel-tall-architect
ephoto/akeneo-connector
emmanuelballery/eb-plantumlbundle
emielburgman/symfony-visitor-beacon
emielburgman/symfony-visit-storage
emielburgman/symfony-security-headers
emielburgman/symfony-log-viewer
emarref/xdebug-bundle
emarref/pubnub-bundle
elriseio/finance-money-bundle