php ecosystem

<php_version> <version_mapping> PHP version-specific feature availability

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "php ecosystem" with this command: npx skills add takeokunn/nixos-configuration/takeokunn-nixos-configuration-php-ecosystem

<php_version> <version_mapping> PHP version-specific feature availability

Property hooks (get/set) Asymmetric visibility (public private(set)) #[Deprecated] attribute Lazy objects new MyClass()->method() without parentheses array_find(), array_find_key(), array_any(), array_all() mb_trim(), mb_ltrim(), mb_rtrim()

Typed class constants json_validate() function Randomizer::getFloat() and nextFloat() Deep cloning of readonly properties Override attribute Granular DateTime exceptions

Readonly classes DNF types (Disjunctive Normal Form) null, false, true as standalone types Constants in traits Deprecate dynamic properties

Enums (backed and unit) Readonly properties Fibers Intersection types never return type First-class callable syntax New in initializers

Named arguments Attributes Constructor property promotion Union types Match expression Nullsafe operator mixed type

</version_mapping>

<recommended_config> php.ini recommended settings for development

error_reporting = E_ALL display_errors = On log_errors = On opcache.enable = 1 opcache.validate_timestamps = 1

</recommended_config> </php_version>

<type_system> <union_types>

Multiple types for parameter or return

function process(string|int $value): string|null { return is_string($value) ? $value : (string) $value; }

</union_types>

<intersection_types>

Value must satisfy all types (PHP 8.1+)

function process(Countable&Iterator $collection): int { return count($collection); }

</intersection_types>

<dnf_types>

Combine union and intersection types (PHP 8.2+)

function handle((Countable&Iterator)|null $items): void { if ($items === null) { return; } foreach ($items as $item) { // process } }

</dnf_types>

    public function label(): string
    {
        return match($this) {
            self::Draft =&#x26;gt; 'Draft',
            self::Published =&#x26;gt; 'Published',
            self::Archived =&#x26;gt; 'Archived',
        };
    }
}

// Usage
$status = Status::from('published');
$value = $status-&#x26;gt;value; // 'published'

</example> </pattern>

<pattern name="unit-enum"> <description>Enum without backing value</description> <example> enum Suit { case Hearts; case Diamonds; case Clubs; case Spades;

    public function color(): string
    {
        return match($this) {
            self::Hearts, self::Diamonds =&#x26;gt; 'red',
            self::Clubs, self::Spades =&#x26;gt; 'black',
        };
    }
}

</example> </pattern>

<pattern name="readonly-class"> <description>All properties become readonly (PHP 8.2+)</description> <example> readonly class ValueObject { public function __construct( public string $name, public int $value, ) {} } </example> </pattern>

class UserController
{
    #[Route('/users', 'GET')]
    public function index(): array
    {
        return [];
    }
}

// Reading attributes via reflection
$method = new ReflectionMethod(UserController::class, 'index');
$attributes = $method-&#x26;gt;getAttributes(Route::class);
foreach ($attributes as $attribute) {
    $route = $attribute-&#x26;gt;newInstance();
    echo $route-&#x26;gt;path; // '/users'
}

</example> </pattern>

<constructor_promotion>

Declare and assign properties in constructor (PHP 8.0+)

class Product { public function __construct( private string $name, private float $price, private int $quantity = 0, ) {}

    public function getName(): string
    {
        return $this-&#x26;gt;name;
    }
}

</example> </pattern>

</constructor_promotion>

<named_arguments>

Pass arguments by name (PHP 8.0+)

function createUser( string $name, string $email, bool $active = true, ?string $role = null, ): User { // ... }

// Usage with named arguments
$user = createUser(
    email: 'user@example.com',
    name: 'John Doe',
    role: 'admin',
);

</example> <decision_tree name="when_to_use"> <question>Are you skipping optional parameters or improving readability?</question> <if_yes>Use named arguments</if_yes> <if_no>Use positional arguments for simple calls</if_no> </decision_tree> </pattern>

</named_arguments>

<typed_class_constants>

Type declarations for class constants (PHP 8.3+)

class Config { public const string VERSION = '1.0.0'; public const int MAX_RETRIES = 3; public const array ALLOWED_METHODS = ['GET', 'POST', 'PUT', 'DELETE']; }

</typed_class_constants>

<property_hooks>

Property hooks for validation and transformation (PHP 8.4+)

class User { public string $email { get => $this->email; set { if (!filter_var($value, FILTER_VALIDATE_EMAIL)) { throw new InvalidArgumentException('Invalid email'); } $this->email = strtolower($value); } } }

<decision_tree name="when_to_use"> Do you need validation or transformation on property access? <if_yes>Use property hooks instead of getters/setters</if_yes> <if_no>Use simple public properties or readonly</if_no> </decision_tree>

<pattern name="virtual-property"> <description>Computed property without backing storage (PHP 8.4+)</description> <example> class User { public string $fullName { get =&gt; $this-&gt;firstName . ' ' . $this-&gt;lastName; }

    public function __construct(
        public string $firstName,
        public string $lastName,
    ) {}
}

</example> </pattern>

<pattern name="old_vs_modern"> <description>Migration from getters/setters to property hooks</description> <old_way> // Before PHP 8.4: Boilerplate getters/setters class Product { private int $price;

    public function getPrice(): int
    {
        return $this-&#x26;gt;price;
    }

    public function setPrice(int $price): void
    {
        if ($price &#x26;lt; 0) {
            throw new InvalidArgumentException('Price cannot be negative');
        }
        $this-&#x26;gt;price = $price;
    }
}

// Usage
$product-&#x26;gt;setPrice(100);
echo $product-&#x26;gt;getPrice();

</old_way> <modern_way> // PHP 8.4+: Property hooks class Product { public int $price { set { if ($value &lt; 0) { throw new InvalidArgumentException('Price cannot be negative'); } $this-&gt;price = $value; } } }

// Usage - direct property access
$product-&#x26;gt;price = 100;
echo $product-&#x26;gt;price;

</modern_way> </pattern>

</property_hooks>

<asymmetric_visibility>

Public read access with private write (PHP 8.4+)

class Order { public private(set) string $status = 'pending'; public private(set) DateTimeImmutable $createdAt; public private(set) ?DateTimeImmutable $processedAt = null;

    public function __construct()
    {
        $this-&#x26;gt;createdAt = new DateTimeImmutable();
    }

    public function process(): void
    {
        $this-&#x26;gt;status = 'processed';
        $this-&#x26;gt;processedAt = new DateTimeImmutable();
    }
}

// Usage
$order = new Order();
echo $order-&#x26;gt;status;       // OK: public read
$order-&#x26;gt;status = 'failed'; // Error: private write

</example> <decision_tree name="when_to_use"> <question>Do you need public read but controlled write access?</question> <if_yes>Use asymmetric visibility (public private(set))</if_yes> <if_no>Use readonly for immutable or regular visibility for mutable</if_no> </decision_tree> </pattern>

</asymmetric_visibility>

<deprecated_attribute>

Mark functions/methods/constants as deprecated (PHP 8.4+)

class ApiService { #[Deprecated( message: 'Use fetchV2() instead', since: '2.0.0' )] public function fetch(): array { return $this->fetchV2(); }

    public function fetchV2(): array
    {
        // New implementation
    }
}

// Usage triggers E_USER_DEPRECATED automatically
$service-&#x26;gt;fetch();

</example> </pattern>

</deprecated_attribute>

<lazy_objects>

Create lazy-initialized objects (PHP 8.4+)

class ExpensiveService { public function __construct() { // Heavy initialization... } }

// Create lazy ghost - initializes only when accessed
$reflector = new ReflectionClass(ExpensiveService::class);
$service = $reflector-&#x26;gt;newLazyGhost(
    function (ExpensiveService $instance) {
        // Called when first property/method accessed
        $instance-&#x26;gt;__construct();
    }
);

// $service not initialized yet
$service-&#x26;gt;doSomething(); // Triggers initialization

</example> <decision_tree name="when_to_use"> <question>Do you need to defer expensive object creation?</question> <if_yes>Use lazy ghost for same-class or lazy proxy for interface wrapping</if_yes> <if_no>Use regular instantiation</if_no> </decision_tree> </pattern>

</lazy_objects> </type_system>

<context7_integration> <library_id>/php/doc-en</library_id> <trust_score>9.4</trust_score>

<usage_pattern> For PHP core documentation, use library ID /php/doc-en Fetch specific topic documentation with get-library-docs </usage_pattern>

<common_queries> PHP attribute syntax and usage Enumeration types and patterns Readonly properties and classes Property hooks syntax (PHP 8.4) </common_queries> </context7_integration>

<psr_standards>

Basic coding standards for PHP files

Files MUST use only <?php and <?= tags Files MUST use only UTF-8 without BOM Class names MUST be declared in StudlyCaps Class constants MUST be declared in UPPER_CASE Method names MUST be declared in camelCase

// File: src/Domain/User/Entity/User.php namespace App\Domain\User\Entity;

class User { // Fully qualified: App\Domain\User\Entity\User } </example>

class UserService { public function __construct( private LoggerInterface $logger, ) {}

  public function create(array $data): User
  {
      $this-&#x26;gt;logger-&#x26;gt;info('Creating user', ['email' =&#x26;gt; $data['email']]);

      try {
          $user = new User($data);
          $this-&#x26;gt;logger-&#x26;gt;debug('User created', ['id' =&#x26;gt; $user-&#x26;gt;getId()]);
          return $user;
      } catch (\Exception $e) {
          $this-&#x26;gt;logger-&#x26;gt;error('Failed to create user', [
              'exception' =&#x26;gt; $e,
              'data' =&#x26;gt; $data,
          ]);
          throw $e;
      }
  }

} </example>

function handleRequest(ServerRequestInterface $request): ResponseInterface { $method = $request-&gt;getMethod(); $uri = $request-&gt;getUri(); $body = $request-&gt;getParsedBody(); $query = $request-&gt;getQueryParams();

  // PSR-7 messages are immutable
  $response = new Response();
  return $response
      -&#x26;gt;withStatus(200)
      -&#x26;gt;withHeader('Content-Type', 'application/json');

} </example>

class ServiceLocator { public function __construct( private ContainerInterface $container, ) {}

  public function getUserService(): UserService
  {
      return $this-&#x26;gt;container-&#x26;gt;get(UserService::class);
  }

} </example>

class AuthMiddleware implements MiddlewareInterface { public function process( ServerRequestInterface $request, RequestHandlerInterface $handler ): ResponseInterface { $token = $request-&gt;getHeaderLine('Authorization');

      if (!$this-&#x26;gt;validateToken($token)) {
          return new Response(401);
      }

      return $handler-&#x26;gt;handle($request);
  }

} </example>

class JsonResponder { public function __construct( private ResponseFactoryInterface $responseFactory, private StreamFactoryInterface $streamFactory, ) {}

  public function respond(array $data, int $status = 200): ResponseInterface
  {
      $json = json_encode($data, JSON_THROW_ON_ERROR);
      $body = $this-&#x26;gt;streamFactory-&#x26;gt;createStream($json);

      return $this-&#x26;gt;responseFactory-&#x26;gt;createResponse($status)
          -&#x26;gt;withHeader('Content-Type', 'application/json')
          -&#x26;gt;withBody($body);
  }

} </example>

class ApiClient { public function __construct( private ClientInterface $httpClient, private RequestFactoryInterface $requestFactory, ) {}

  public function get(string $url): array
  {
      $request = $this-&#x26;gt;requestFactory-&#x26;gt;createRequest('GET', $url);
      $response = $this-&#x26;gt;httpClient-&#x26;gt;sendRequest($request);

      return json_decode(
          $response-&#x26;gt;getBody()-&#x26;gt;getContents(),
          true,
          512,
          JSON_THROW_ON_ERROR
      );
  }

} </example>

<design_patterns>

Immutable objects representing a value

readonly class Money { public function __construct( public int $amount, public string $currency, ) { if ($amount < 0) { throw new InvalidArgumentException('Amount cannot be negative'); } }

  public function add(Money $other): self
  {
      if ($this-&#x26;gt;currency !== $other-&#x26;gt;currency) {
          throw new InvalidArgumentException('Currency mismatch');
      }
      return new self($this-&#x26;gt;amount + $other-&#x26;gt;amount, $this-&#x26;gt;currency);
  }

  public function equals(Money $other): bool
  {
      return $this-&#x26;gt;amount === $other-&#x26;gt;amount
          &#x26;amp;&#x26;amp; $this-&#x26;gt;currency === $other-&#x26;gt;currency;
  }

} </example>

class PdoUserRepository implements UserRepositoryInterface { public function __construct( private PDO $pdo, ) {}

  public function find(UserId $id): ?User
  {
      $stmt = $this-&#x26;gt;pdo-&#x26;gt;prepare(
          'SELECT * FROM users WHERE id = :id'
      );
      $stmt-&#x26;gt;execute(['id' =&#x26;gt; $id-&#x26;gt;toString()]);
      $row = $stmt-&#x26;gt;fetch(PDO::FETCH_ASSOC);

      return $row ? $this-&#x26;gt;hydrate($row) : null;
  }

  public function save(User $user): void
  {
      $stmt = $this-&#x26;gt;pdo-&#x26;gt;prepare(
          'INSERT INTO users (id, email, name)
           VALUES (:id, :email, :name)
           ON DUPLICATE KEY UPDATE email = :email, name = :name'
      );
      $stmt-&#x26;gt;execute([
          'id' =&#x26;gt; $user-&#x26;gt;getId()-&#x26;gt;toString(),
          'email' =&#x26;gt; $user-&#x26;gt;getEmail()-&#x26;gt;toString(),
          'name' =&#x26;gt; $user-&#x26;gt;getName(),
      ]);
  }

} </example> <decision_tree name="when_to_use"> <question>Do you need to abstract persistence details from domain logic?</question> <if_yes>Use Repository pattern</if_yes> <if_no>Direct database access may be sufficient for simple CRUD</if_no> </decision_tree>

  public function handle(CreateUserCommand $command): UserId
  {
      $email = new Email($command-&#x26;gt;email);

      if ($this-&#x26;gt;userRepository-&#x26;gt;findByEmail($email) !== null) {
          throw new UserAlreadyExistsException($email);
      }

      $user = User::create(
          UserId::generate(),
          $email,
          $command-&#x26;gt;name,
          $this-&#x26;gt;passwordHasher-&#x26;gt;hash($command-&#x26;gt;password),
      );

      $this-&#x26;gt;userRepository-&#x26;gt;save($user);
      $this-&#x26;gt;eventDispatcher-&#x26;gt;dispatch(new UserCreatedEvent($user));

      return $user-&#x26;gt;getId();
  }

} </example>

// Concrete implementation class RedisCache implements CacheInterface { public function __construct( private \Redis $redis, ) {}

  public function get(string $key): mixed
  {
      $value = $this-&#x26;gt;redis-&#x26;gt;get($key);
      return $value !== false ? unserialize($value) : null;
  }

  public function set(string $key, mixed $value, int $ttl = 3600): void
  {
      $this-&#x26;gt;redis-&#x26;gt;setex($key, $ttl, serialize($value));
  }

}

// Service depending on abstraction class ProductService { public function __construct( private ProductRepositoryInterface $repository, private CacheInterface $cache, ) {} } </example>

<pattern name="require-dev"> <description>Add development dependencies</description> <example> composer require --dev phpunit/phpunit composer require --dev phpstan/phpstan composer require --dev friendsofphp/php-cs-fixer </example> </pattern>

<pattern name="version-constraints"> <description>Specify version requirements</description> <example> { "require": { "php": "^8.3", "psr/log": "^3.0", "guzzlehttp/guzzle": "^7.0" }, "require-dev": { "phpunit/phpunit": "^10.0 || ^11.0", "phpstan/phpstan": "^1.10" } } </example> <note>^ allows minor version updates, ~ allows patch updates only</note> </pattern>

</package_management>

<package_development>

Standard library package structure

my-package/ ├── src/ │ └── MyClass.php ├── tests/ │ └── MyClassTest.php ├── composer.json ├── phpunit.xml.dist ├── phpstan.neon ├── .php-cs-fixer.dist.php ├── LICENSE └── README.md

<pattern name="composer-json"> <description>Complete composer.json for library</description> <example> { "name": "vendor/my-package", "description": "My awesome PHP package", "type": "library", "license": "MIT", "authors": [ { "name": "Your Name", "email": "you@example.com" } ], "require": { "php": "^8.2" }, "require-dev": { "phpunit/phpunit": "^11.0", "phpstan/phpstan": "^1.10" }, "autoload": { "psr-4": { "Vendor\MyPackage\": "src/" } }, "autoload-dev": { "psr-4": { "Vendor\MyPackage\Tests\": "tests/" } }, "scripts": { "test": "phpunit", "analyse": "phpstan analyse", "cs-fix": "php-cs-fixer fix" }, "config": { "sort-packages": true } } </example> </pattern>

<pattern name="scripts"> <description>Automate common tasks with Composer scripts</description> <example> { "scripts": { "test": "phpunit --colors=always", "test:coverage": "phpunit --coverage-html coverage", "analyse": "phpstan analyse --memory-limit=512M", "cs-check": "php-cs-fixer fix --dry-run --diff", "cs-fix": "php-cs-fixer fix", "ci": [ "@cs-check", "@analyse", "@test" ] } } </example> </pattern>

</package_development>

class CalculatorTest extends TestCase
{
    private Calculator $calculator;

    protected function setUp(): void
    {
        $this-&#x26;gt;calculator = new Calculator();
    }

    #[Test]
    public function itAddsNumbers(): void
    {
        $result = $this-&#x26;gt;calculator-&#x26;gt;add(2, 3);

        $this-&#x26;gt;assertSame(5, $result);
    }

    #[Test]
    #[DataProvider('additionProvider')]
    public function itAddsVariousNumbers(int $a, int $b, int $expected): void
    {
        $this-&#x26;gt;assertSame($expected, $this-&#x26;gt;calculator-&#x26;gt;add($a, $b));
    }

    public static function additionProvider(): array
    {
        return [
            'positive numbers' =&#x26;gt; [1, 2, 3],
            'negative numbers' =&#x26;gt; [-1, -2, -3],
            'mixed numbers' =&#x26;gt; [-1, 2, 1],
            'zeros' =&#x26;gt; [0, 0, 0],
        ];
    }
}

</example> </pattern>

<pattern name="mocking"> <description>Create test doubles with PHPUnit</description> <example> use PHPUnit\Framework\TestCase;

class UserServiceTest extends TestCase
{
    #[Test]
    public function itCreatesUser(): void
    {
        // Arrange
        $repository = $this-&#x26;gt;createMock(UserRepositoryInterface::class);
        $repository
            -&#x26;gt;expects($this-&#x26;gt;once())
            -&#x26;gt;method('save')
            -&#x26;gt;with($this-&#x26;gt;isInstanceOf(User::class));

        $hasher = $this-&#x26;gt;createMock(PasswordHasherInterface::class);
        $hasher
            -&#x26;gt;method('hash')
            -&#x26;gt;willReturn('hashed_password');

        $service = new UserService($repository, $hasher);

        // Act
        $userId = $service-&#x26;gt;create('test@example.com', 'password');

        // Assert
        $this-&#x26;gt;assertInstanceOf(UserId::class, $userId);
    }
}

</example> </pattern>

<pattern name="config"> <description>PHPUnit configuration file</description> <example> &lt;!-- phpunit.xml.dist --&gt; &lt;?xml version="1.0" encoding="UTF-8"?&gt; &lt;phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd" bootstrap="vendor/autoload.php" colors="true" cacheDirectory=".phpunit.cache"&gt; &lt;testsuites&gt; &lt;testsuite name="Unit"&gt; &lt;directory&gt;tests/Unit&lt;/directory&gt; &lt;/testsuite&gt; &lt;testsuite name="Integration"&gt; &lt;directory&gt;tests/Integration&lt;/directory&gt; &lt;/testsuite&gt; &lt;/testsuites&gt; &lt;source&gt; &lt;include&gt; &lt;directory&gt;src&lt;/directory&gt; &lt;/include&gt; &lt;/source&gt; &lt;/phpunit&gt; </example> </pattern>

beforeEach(function () {
    $this-&#x26;gt;calculator = new Calculator();
});

test('it adds numbers', function () {
    expect($this-&#x26;gt;calculator-&#x26;gt;add(2, 3))-&#x26;gt;toBe(5);
});

test('it subtracts numbers', function () {
    expect($this-&#x26;gt;calculator-&#x26;gt;subtract(5, 3))-&#x26;gt;toBe(2);
});

it('throws on division by zero', function () {
    $this-&#x26;gt;calculator-&#x26;gt;divide(10, 0);
})-&#x26;gt;throws(DivisionByZeroError::class);

</example> </pattern>

<pattern name="datasets"> <description>Pest datasets for parameterized tests</description> <example> dataset('addition', [ 'positive' =&gt; [1, 2, 3], 'negative' =&gt; [-1, -2, -3], 'mixed' =&gt; [-1, 2, 1], ]);

test('it adds numbers correctly', function (int $a, int $b, int $expected) {
    expect($this-&#x26;gt;calculator-&#x26;gt;add($a, $b))-&#x26;gt;toBe($expected);
})-&#x26;gt;with('addition');

</example> </pattern>

<pattern name="expectations"> <description>Pest expectation API</description> <example> test('user properties', function () { $user = new User('john@example.com', 'John Doe');

    expect($user)
        -&#x26;gt;toBeInstanceOf(User::class)
        -&#x26;gt;email-&#x26;gt;toBe('john@example.com')
        -&#x26;gt;name-&#x26;gt;toBe('John Doe')
        -&#x26;gt;isActive()-&#x26;gt;toBeTrue();
});

</example> </pattern>

<static_analysis>

PHPStan configuration

phpstan.neon

parameters: level: 8 paths:

  • src
  • tests excludePaths:
  • vendor checkMissingIterableValueType: true checkGenericClassInNonGenericObjectType: true reportUnmatchedIgnoredErrors: true

<pattern name="levels"> <description>PHPStan strictness levels (0-9)</description> <levels> <level number="0">Basic checks</level> <level number="1">Possibly undefined variables</level> <level number="2">Unknown methods on $this</level> <level number="3">Wrong return types</level> <level number="4">Dead code</level> <level number="5">Argument types</level> <level number="6">Missing type hints</level> <level number="7">Partial union types</level> <level number="8">No mixed types</level> <level number="9">Mixed type operations</level> <level number="10">Stricter implicit mixed (PHPStan 2.0+)</level> </levels> <note>Start at level 5-6 for existing projects, level 9-10 for new projects. Use --level max for highest available.</note> </pattern>

<pattern name="level-9-10-config"> <description>Maximum strictness configuration for new projects</description> <example> # phpstan.neon includes: - vendor/phpstan/phpstan-strict-rules/rules.neon

parameters:
    level: 10  # PHPStan 2.0+ (use 9 for PHPStan 1.x)
    paths:
        - src
        - tests
    checkUninitializedProperties: true
    checkBenevolentUnionTypes: true
    reportPossiblyNonexistentGeneralArrayOffset: true

</example> <note>Level 10 treats implicit mixed (missing types) as strictly as explicit mixed. Use phpstan-strict-rules for additional checks like === enforcement.</note> </pattern>

<pattern name="generics"> <description>Generic types with PHPStan annotations</description> <example> /** * @template T * @param class-string&lt;T&gt; $class * @return T */ public function create(string $class): object { return new $class(); }

/**
 * @template T of object
 * @param T $entity
 * @return T
 */
public function save(object $entity): object
{
    // persist
    return $entity;
}

</example> </pattern>

<pattern name="annotations"> <description>Psalm-specific annotations</description> <example> /** * @psalm-immutable */ readonly class ImmutableValue { public function __construct( public string $value, ) {} }

/**
 * @psalm-assert-if-true User $user
 */
function isActiveUser(?User $user): bool
{
    return $user !== null &#x26;amp;&#x26;amp; $user-&#x26;gt;isActive();
}

</example> </pattern>

<php_cs_fixer>

PHP CS Fixer configuration

<?php // .php-cs-fixer.dist.php $finder = PhpCsFixer\Finder::create() ->in(DIR . '/src') ->in(DIR . '/tests');

return (new PhpCsFixer\Config())
    -&#x26;gt;setRules([
        '@PER-CS' =&#x26;gt; true,
        '@PHP84Migration' =&#x26;gt; true,
        'strict_types' =&#x26;gt; true,
        'declare_strict_types' =&#x26;gt; true,
        'array_syntax' =&#x26;gt; ['syntax' =&#x26;gt; 'short'],
        'no_unused_imports' =&#x26;gt; true,
        'ordered_imports' =&#x26;gt; ['sort_algorithm' =&#x26;gt; 'alpha'],
        'trailing_comma_in_multiline' =&#x26;gt; true,
    ])
    -&#x26;gt;setFinder($finder)
    -&#x26;gt;setRiskyAllowed(true);

</example> </pattern>

</php_cs_fixer>

return RectorConfig::configure()
    -&#x26;gt;withPaths([
        __DIR__ . '/src',
        __DIR__ . '/tests',
    ])
    -&#x26;gt;withSets([
        SetList::CODE_QUALITY,
        SetList::DEAD_CODE,
        SetList::TYPE_DECLARATION,
    ])
    -&#x26;gt;withPhpSets(php84: true);

</example> <note>LevelSetList (e.g., UP_TO_PHP_84) deprecated since Rector 0.19.2. Use -&gt;withPhpSets() instead.</note> </pattern>

$pdo = new PDO($dsn, $username, $password, $options);

</example> </pattern>

<pattern name="prepared-statements"> <description>Secure parameterized queries</description> <example> // Named parameters $stmt = $pdo-&gt;prepare('SELECT * FROM users WHERE email = :email'); $stmt-&gt;execute(['email' =&gt; $email]); $user = $stmt-&gt;fetch();

// Positional parameters
$stmt = $pdo-&#x26;gt;prepare('INSERT INTO users (email, name) VALUES (?, ?)');
$stmt-&#x26;gt;execute([$email, $name]);
$id = $pdo-&#x26;gt;lastInsertId();

</example> <warning>Never concatenate user input into SQL queries</warning> </pattern>

<pattern name="transactions"> <description>Database transactions with PDO</description> <example> try { $pdo-&gt;beginTransaction();

    $stmt = $pdo-&#x26;gt;prepare('UPDATE accounts SET balance = balance - ? WHERE id = ?');
    $stmt-&#x26;gt;execute([$amount, $fromAccount]);

    $stmt = $pdo-&#x26;gt;prepare('UPDATE accounts SET balance = balance + ? WHERE id = ?');
    $stmt-&#x26;gt;execute([$amount, $toAccount]);

    $pdo-&#x26;gt;commit();
} catch (\Exception $e) {
    $pdo-&#x26;gt;rollBack();
    throw $e;
}

</example> </pattern>

// Preload commonly used classes
$classesToPreload = [
    App\Domain\User\User::class,
    App\Domain\Order\Order::class,
];

foreach ($classesToPreload as $class) {
    class_exists($class);
}

</example> <config> ; php.ini opcache.preload=/path/to/preload.php opcache.preload_user=www-data </config> </pattern>

<error_handling>

Custom exception hierarchy

// Base domain exception abstract class DomainException extends \Exception {}

// Specific exceptions class EntityNotFoundException extends DomainException { public static function forClass(string $class, string $id): self { return new self(sprintf('%s with id "%s" not found', $class, $id)); } }

class ValidationException extends DomainException { public function __construct( string $message, public readonly array $errors = [], ) { parent::__construct($message); } }

// Usage throw EntityNotFoundException::forClass(User::class, $userId); </example>

  /** @return self&#x26;lt;T, never&#x26;gt; */
  public static function ok(mixed $value): self
  {
      return new self(true, $value);
  }

  /** @return self&#x26;lt;never, E&#x26;gt; */
  public static function error(mixed $error): self
  {
      return new self(false, $error);
  }

  public function isSuccess(): bool { return $this-&#x26;gt;success; }
  public function isError(): bool { return !$this-&#x26;gt;success; }
  public function getValue(): mixed { return $this-&#x26;gt;value; }

}

// Usage function divide(int $a, int $b): Result { if ($b === 0) { return Result::error('Division by zero'); } return Result::ok($a / $b); } </example>

<array_functions> <php84_functions>

Find first element matching predicate (PHP 8.4+)

$users = [ ['id' => 1, 'active' => false], ['id' => 2, 'active' => true], ['id' => 3, 'active' => true], ];

$firstActive = array_find($users, fn($user) =&#x26;gt; $user['active']);
// ['id' =&#x26;gt; 2, 'active' =&#x26;gt; true]

</example> </function>

<function name="array_find_key"> <description>Find key of first element matching predicate (PHP 8.4+)</description> <example> $users = [ 'john' =&gt; ['active' =&gt; false], 'jane' =&gt; ['active' =&gt; true], ];

$firstActiveKey = array_find_key($users, fn($user) =&#x26;gt; $user['active']);
// 'jane'

</example> </function>

<function name="array_any"> <description>Check if any element matches predicate (PHP 8.4+)</description> <example> $hasAdmin = array_any($users, fn($u) =&gt; $u['role'] === 'admin'); </example> </function>

<function name="array_all"> <description>Check if all elements match predicate (PHP 8.4+)</description> <example> $allActive = array_all($users, fn($u) =&gt; $u['active']); </example> </function>

</php84_functions> </array_functions>

<anti_patterns>

Classes that do too much Split into focused single-responsibility classes

// Good $stmt = $pdo-&gt;prepare('SELECT * FROM users WHERE email = ?'); $stmt-&gt;execute([$email]); </example>

<best_practices> Enable strict_types in all PHP files Use prepared statements for all database queries Use PHPStan level 9+ for type safety Use readonly classes for value objects Follow PSR-12 coding style Use enums instead of string/int constants Inject dependencies through constructor Use named arguments for complex function calls Create custom exceptions for domain errors Use attributes for metadata instead of docblock annotations </best_practices>

<error_escalation>

Minor coding style issue Auto-fix with PHP CS Fixer

PHPStan error or missing type Fix type, verify with static analysis

Breaking API change or security issue Stop, present options to user

SQL injection or authentication bypass Block operation, require immediate fix

</error_escalation>

<related_skills> Symbol-level navigation for class and interface definitions Fetch latest PHP and library documentation Test strategy and coverage patterns PDO patterns and query optimization </related_skills>

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

devenv ecosystem

No summary provided by upstream source.

Repository SourceNeeds Review
General

test_skill

import json import tkinter as tk from tkinter import messagebox, simpledialog

Archived SourceRecently Updated
General

错敏信息检测

1. 安装https://clawhub.ai/xxxx/sensitive-check-skill 这个技能 2. 调用错敏信息检测技能,传入参数 userKey=xxxx,content=xxxx

Archived SourceRecently Updated
General

neo

Browse websites, read web pages, interact with web apps, call website APIs, and automate web tasks. Use Neo when: user asks to check a website, read a web page, post on social media (Twitter/X), interact with any web app, look up information on a specific site, scrape data from websites, automate browser tasks, or when you need to call any website's API. Keywords: website, web page, browse, URL, http, API, twitter, tweet, post, scrape, web app, open site, check site, read page, social media, online service.

Archived SourceRecently Updated