用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/personamanagmentlayer/pcl --skill php-expert命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
Expert in Persona Control Language (PCL) - language design, compiler architecture, runtime systems, and ecosystem development
Expert system for designing, creating, and validating PCL skills with comprehensive domain knowledge extraction
Expert-level Docker containerization, image optimization, and container orchestration. Use this skill for building efficient Docker images, managing containers, and implementing Docker best practices.
基于 SOC 职业分类
正在显示 SKILL.md
| name | php-expert |
| version | 1.0.0 |
| description | Expert-level PHP development with PHP 8+, Laravel, Composer, and modern best practices |
| category | languages |
| tags | ["php","laravel","composer","symfony","phpunit","psr"] |
| allowed-tools | ["Read","Write","Edit","Bash(php:*, composer:*, artisan:*)"] |
Expert guidance for modern PHP development including PHP 8+ features, Laravel framework, Composer dependency management, and PHP best practices.
<?php
// Before PHP 8
class User {
private string $name;
private string $email;
private int $age;
public function __construct(string $name, string $email, int $age) {
$this->name = $name;
$this->email = $email;
$this->age = $age;
}
}
// PHP 8+ (constructor property promotion)
class User {
public function __construct(
private string $name,
private string $email,
private int $age,
) {}
public function getName(): string {
return ->name;
}
}
= (, , );
<?php
function createUser(
string $name,
string $email,
int $age = 18,
bool $admin = false,
): User {
return new User($name, $email, $age, $admin);
}
// Named arguments (PHP 8+)
$user = createUser(
name: 'Alice',
email: 'alice@example.com',
age: 30,
admin: true,
);
// Skip optional parameters
$user = createUser(
name: 'Bob',
email: 'bob@example.com',
);
<?php
// Union types (PHP 8+)
function processValue(int|float $number): int|float {
return $number * 2;
}
function findUser(int|string $identifier): ?User {
if (is_int($identifier)) {
return User::find($identifier);
}
return User::where('email', $identifier)->first();
}
// Mixed type (accepts any type)
function debugValue(mixed $value): void {
var_dump($value);
}
<?php
// Old switch
switch ($status) {
case 'pending':
$message = 'Order is pending';
break;
case 'processing':
$message = 'Order is being processed';
break;
case 'completed':
$message = 'Order completed';
break;
default:
$message = 'Unknown status';
}
// Match expression (PHP 8+)
$message = match ($status) {
'pending' => 'Order is pending',
'processing' => 'Order is being processed',
'completed' => 'Order completed',
default => 'Unknown status',
};
// Multiple conditions
$result = match ($value) {
0, 1, 2 => 'Small',
3, 4, 5 => 'Medium',
default => 'Large',
};
// With expressions
$discount = match (true) {
->() && ->() > => ,
->() => ,
->() > => ,
=> ,
};
<?php
// Before PHP 8
$country = null;
if ($user !== null) {
$address = $user->getAddress();
if ($address !== null) {
$country = $address->getCountry();
}
}
// PHP 8+ nullsafe operator
$country = $user?->getAddress()?->getCountry();
// With default
$country = $user?->getAddress()?->getCountry() ?? 'Unknown';
<?php
// Define attribute
#[Attribute]
class Route {
public function __construct(
public string $path,
public string $method = 'GET',
) {}
}
// Use attribute
class UserController {
#[Route('/users', method: 'GET')]
public function index(): array {
return User::all();
}
#[Route('/users/{id}', method: 'GET')]
public function show(int $id): User {
return User::findOrFail($id);
}
#[Route('/users', method: 'POST')
{
::(->());
}
}
= (::);
(->() ) {
= ->(::);
( ) {
= ->();
;
}
}
<?php
// Basic enum
enum Status {
case Pending;
case Processing;
case Completed;
case Cancelled;
}
// Usage
$status = Status::Pending;
function updateOrder(Order $order, Status $status): void {
$order->status = $status;
$order->save();
}
// Backed enums
enum OrderStatus: string {
case Pending = 'pending';
case Processing = 'processing';
case Completed = 'completed';
case Cancelled = 'cancelled';
public function label(): string {
return match($this) {
self::Pending => 'Pending',
self::Processing => 'Being Processed',
self:: => ,
:: => ,
};
}
{
() {
:: => ,
:: => ,
:: => ,
:: => ,
};
}
}
= ::();
->();
->value;
<?php
// Readonly property (PHP 8.1+)
class User {
public function __construct(
public readonly string $id,
public readonly string $email,
public string $name,
) {}
}
$user = new User('123', 'user@example.com', 'Alice');
$user->name = 'Bob'; // OK
// $user->email = 'new@example.com'; // Error: readonly property
// Readonly class (PHP 8.2+)
readonly class Point {
public function __construct(
public int $x,
public int $y,
) {}
}
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\SoftDeletes;
class User extends Model
{
use SoftDeletes;
protected $fillable = [
'name',
'email',
'password',
];
protected $hidden = [
'password',
'remember_token',
];
protected $casts = [
'email_verified_at' => 'datetime',
'is_admin' => 'boolean',
'settings' => 'array',
];
// Relationships
public function ():
{
->(::);
}
{
->(::);
}
{
::(
: fn ( ) => (),
set: (),
);
}
{
->(, );
}
{
->(, );
}
{
->is_admin;
}
}
= ::()->();
= ::()->();
= ::(, )->();
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Http\Requests\StorePostRequest;
use App\Http\Requests\UpdatePostRequest;
use App\Http\Resources\PostResource;
use App\Models\Post;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
class PostController extends Controller
{
public function __construct()
{
$this->middleware('auth:api')->except(['index', 'show']);
}
public {
= ::()
->()
->()
->();
::();
}
{
->([, ]);
();
}
{
= ->()->()->(
->()
);
()->(
(),
);
}
{
->(, );
->(->());
();
}
{
->(, );
->();
()->(, );
}
}
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StorePostRequest extends FormRequest
{
public function authorize(): bool
{
return $this->user() !== null;
}
public function rules(): array
{
return [
'title' => ['required', 'string', 'max:200'],
'content' => ['required', 'string', 'min:100'],
'published' => ['sometimes', 'boolean'],
'tags' => ['sometimes', 'array'],
'tags.*' => ['string', 'max:50'],
];
}
public function messages(): array
{
[
=> ,
=> ,
];
}
}
<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class PostResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'title' => $this->title,
'slug' => $this->slug,
'content' => $this->when(
$request->routeIs('posts.show'),
$this->content
),
'excerpt' => $this->excerpt,
'published' => $this->published,
'published_at' => $this->published_at?->toIso8601String(),
'author' => new UserResource(->()),
=> ::(
->()
),
=> ->tags,
=> ->created_at->(),
=> ->updated_at->(),
];
}
}
<?php
// Basic queries
$users = User::all();
$user = User::find(1);
$user = User::where('email', 'user@example.com')->first();
// Complex queries
$posts = Post::where('published', true)
->where('created_at', '>', now()->subWeek())
->orderBy('created_at', 'desc')
->limit(10)
->get();
// Eager loading (avoid N+1)
$posts = Post::with(['user', 'comments.user'])->get();
// Lazy eager loading
$posts = Post::all();
$posts->load('user');
// Conditional loading
$posts = Post::with([
=> function () {
->(, , );
},
=> {
->()->();
},
])->();
= ::(, )->();
= ::(, )->();
= ::();
::(, function () {
( ) {
}
});
DB::(function () ($) {
$ = ::($['']);
= ->()->([]);
->()->([]);
});
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->string('title');
$table->string('slug')->unique();
$table->text('content');
$table->text('excerpt')->nullable();
->()->();
->()->();
->()->();
->();
->();
->();
->();
->([, ]);
});
}
{
::();
}
};
<?php
namespace App\Jobs;
use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class SendWelcomeEmail implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public function __construct(
public User $user,
) {}
public function handle(): void
{
Mail::to($this->user->email)
->send( (->user));
}
{
::(, [
=> ->user->id,
=> ->(),
]);
}
}
::();
::()->(()->());
::()->();
<?php
// Event
namespace App\Events;
use App\Models\Post;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class PostPublished
{
use Dispatchable, SerializesModels;
public function __construct(
public Post $post,
) {}
}
// Listener
namespace App\Listeners;
use App\Events\PostPublished;
use App\Notifications\NewPostNotification;
class NotifyFollowers
{
public function handle(PostPublished $event): void
{
$followers = $event->post->user->followers;
foreach ( ) {
->( (->post));
}
}
}
= [
:: => [
::,
],
];
::();
<?php
namespace Tests\Feature;
use App\Models\User;
use App\Models\Post;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class PostControllerTest extends TestCase
{
use RefreshDatabase;
public function test_can_list_posts(): void
{
Post::factory()->count(3)->create(['published' => true]);
Post::factory()->create(['published' => false]);
$response = $this->getJson('/api/posts');
$response->assertOk()
->assertJsonCount(3, 'data');
}
{
= ::()->();
= ->(, )
->(, [
=> ,
=> ,
]);
->()
->(, );
->(, [
=> ,
=> ->id,
]);
}
{
= ->(, [
=> ,
=> ,
]);
->();
}
{
= ::()->();
= ->(, )
->(, [
=> , // Invalid
=> , // Too short
]);
->()
->([, ]);
}
{
= ::()->();
= ::()->([ => ->id]);
= ->(, )
->(, [
=> ,
=> ,
]);
->();
->(, [
=> ->id,
=> ,
]);
}
{
= ::()->();
= ::()->();
= ::()->([ => ->id]);
= ->(, )
->(, [
=> ,
]);
->();
}
}
<?php
namespace Tests\Unit;
use App\Models\User;
use App\Models\Post;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class UserTest extends TestCase
{
use RefreshDatabase;
public function test_user_has_posts(): void
{
$user = User::factory()->create();
$posts = Post::factory()->count(3)->create(['user_id' => $user->id]);
$this->assertCount(3, $user->posts);
$this->assertTrue($user->posts->contains($posts->()));
}
{
= ::()->([ => ]);
= ::()->([ => ]);
->(->());
->(->());
}
}
<?php
namespace Database\Factories;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
class PostFactory extends Factory
{
public function definition(): array
{
return [
'user_id' => User::factory(),
'title' => fake()->sentence(),
'slug' => fake()->slug(),
'content' => fake()->paragraphs(5, true),
'excerpt' => fake()->paragraph(),
'published' => false,
'published_at' => null,
'tags' => fake()->words(3),
];
}
public {
->(fn ( ) => [
=> ,
=> (),
]);
}
{
->(fn ( ) => [
=> ->id,
]);
}
}
<?php
declare(strict_types=1);
// Always use strict types
// Use type declarations for parameters and return types
// Use property types where possible
<?php
// Use constructor injection
class UserService
{
public function __construct(
private UserRepository $repository,
private EventDispatcher $dispatcher,
) {}
public function createUser(array $data): User
{
$user = $this->repository->create($data);
$this->dispatcher->dispatch(new UserCreated($user));
return $user;
}
}
❌ Not using strict types: Always declare(strict_types=1) ❌ Fat controllers: Extract logic to services ❌ N+1 queries: Use eager loading ❌ No type declarations: Use types everywhere ❌ Ignoring PSR standards: Follow PSR-4, PSR-12 ❌ Direct DB queries in controllers: Use repositories ❌ Missing validation: Always validate input ❌ No tests: Write tests for critical code