一键导入
performance-guide
Performance optimization for PHP, JavaScript, databases, and caching strategies
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Performance optimization for PHP, JavaScript, databases, and caching strategies
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
RESTful API design patterns, HTTP standards, versioning, error handling, and documentation
Joomla 4/5 component development with MVC, services, plugins, and language handling
Joomla 3.x legacy patterns with JFactory, non-namespaced MVC, JDatabase, and plugin structure
Laravel best practices for Eloquent, controllers, validation, services, and testing
PHP coding standards including strict typing, OOP patterns, error handling, and documentation
Deep dive into SOLID principles with PHP/TypeScript examples, refactoring patterns, and violation detection
| name | performance-guide |
| description | Performance optimization for PHP, JavaScript, databases, and caching strategies |
| license | MIT |
| compatibility | opencode |
| metadata | {"type":"optimization","languages":"php, javascript, sql"} |
Problem:
$users = User::all();
foreach ($users as $user) {
echo $user->profile->bio; // Query per user!
}
// 1 query for users + N queries for profiles = N+1
Solution - Eager Loading:
// Laravel
$users = User::with('profile')->get();
// Doctrine
$qb->select('u', 'p')
->from(User::class, 'u')
->leftJoin('u.profile', 'p');
// Joomla
$query->select($db->quoteName(['u.*', 'p.bio']))
->from($db->quoteName('#__users', 'u'))
->leftJoin($db->quoteName('#__profiles', 'p') . ' ON p.user_id = u.id');
// Bad
$users = User::all(); // SELECT *
// Good
$users = User::select(['id', 'name', 'email'])->get();
-- Index columns used in:
-- WHERE clauses
CREATE INDEX idx_users_status ON users(status);
-- JOIN conditions
CREATE INDEX idx_orders_user_id ON orders(user_id);
-- ORDER BY
CREATE INDEX idx_posts_created_at ON posts(created_at DESC);
-- Composite for common queries
CREATE INDEX idx_orders_user_status ON orders(user_id, status);
-- MySQL
EXPLAIN SELECT * FROM users WHERE status = 'active';
-- Look for:
-- type: ALL (bad) vs index/ref (good)
-- rows: Lower is better
-- Extra: "Using filesort" or "Using temporary" = potential issue
// Bad - loads all into memory
User::all()->each(fn($user) => process($user));
// Good - processes in chunks
User::chunk(1000, function ($users) {
foreach ($users as $user) {
process($user);
}
});
// Laravel lazy collection
User::lazy()->each(fn($user) => process($user));
// Bad
foreach ($items as $item) {
$count = count($items); // Recalculated each iteration
// ...
}
// Good
$count = count($items);
foreach ($items as $item) {
// Use $count
}
// For checking existence - O(1) vs O(n)
// Bad
$allowed = ['admin', 'moderator', 'user'];
if (in_array($role, $allowed)) { }
// Good
$allowed = ['admin' => true, 'moderator' => true, 'user' => true];
if (isset($allowed[$role])) { }
// Bad for many concatenations
$html = '';
foreach ($items as $item) {
$html .= '<li>' . $item . '</li>';
}
// Better
$parts = [];
foreach ($items as $item) {
$parts[] = '<li>' . $item . '</li>';
}
$html = implode('', $parts);
// Best - use output buffering or templates
// Bad - loads all into memory
function getUsers(): array
{
return User::all()->toArray();
}
// Good - yields one at a time
function getUsers(): Generator
{
foreach (User::cursor() as $user) {
yield $user;
}
}
<template>
<!-- Use v-once for static content -->
<header v-once>{{ staticTitle }}</header>
<!-- Use v-memo for expensive re-renders -->
<div v-memo="[item.id, item.selected]">
<ExpensiveComponent :item="item" />
</div>
<!-- Always key v-for -->
<div v-for="item in items" :key="item.id">
{{ item.name }}
</div>
</template>
// Components
const HeavyComponent = defineAsyncComponent(() =>
import('./HeavyComponent.vue')
)
// Routes
const routes = [
{
path: '/dashboard',
component: () => import('./views/Dashboard.vue')
}
]
import { useDebounceFn, useThrottleFn } from '@vueuse/core'
// Debounce - wait until user stops typing
const search = useDebounceFn((query: string) => {
fetchResults(query)
}, 300)
// Throttle - max once per interval
const scroll = useThrottleFn(() => {
updateScrollPosition()
}, 100)
// worker.ts
self.onmessage = (e) => {
const result = heavyComputation(e.data)
self.postMessage(result)
}
// main.ts
const worker = new Worker('./worker.ts')
worker.postMessage(data)
worker.onmessage = (e) => {
result.value = e.data
}
Request → Application Cache → Database Cache → Database
(Redis/Memcached) (Query Cache)
// Simple cache
$users = Cache::remember('users:active', 3600, function () {
return User::where('status', 'active')->get();
});
// Tagged cache (for invalidation)
Cache::tags(['users'])->put("user:{$id}", $user, 3600);
Cache::tags(['users'])->flush(); // Clear all user cache
// Cache with lock (prevent stampede)
$users = Cache::lock('users:lock')->block(5, function () {
return Cache::remember('users:all', 3600, fn() => User::all());
});
return response($content)
->header('Cache-Control', 'public, max-age=3600')
->header('ETag', md5($content));
| Tool | Use Case |
|---|---|
| Xdebug | PHP step debugging & profiling |
| Blackfire | PHP performance profiling |
| Laravel Telescope | Request/query debugging |
| Symfony Profiler | Built-in profiling toolbar |
| Chrome DevTools | JS performance & network |
| Vue DevTools | Component render performance |
EXPLAIN ANALYZE | SQL query analysis |