acc-detect-unnecessary-loops

📁 dykyi-roman/awesome-claude-code 📅 2 days ago
1
总安装量
1
周安装量
#48249
全站排名
安装命令
npx skills add https://github.com/dykyi-roman/awesome-claude-code --skill acc-detect-unnecessary-loops

Agent 安装分布

opencode 1
claude-code 1

Skill 文档

Unnecessary Loop Detection

Analyze PHP code for inefficient loop patterns.

Detection Patterns

1. Nested Loop Inefficiency

// O(n*m): Nested search
foreach ($users as $user) {
    foreach ($orders as $order) {
        if ($order->getUserId() === $user->getId()) {
            // Found order for user
        }
    }
}

// O(n): Use indexed lookup
$ordersByUser = [];
foreach ($orders as $order) {
    $ordersByUser[$order->getUserId()][] = $order;
}
foreach ($users as $user) {
    $userOrders = $ordersByUser[$user->getId()] ?? [];
}

2. Redundant Iterations

// REDUNDANT: Multiple passes
$filtered = [];
foreach ($items as $item) {
    if ($item->isActive()) {
        $filtered[] = $item;
    }
}
$transformed = [];
foreach ($filtered as $item) {
    $transformed[] = $item->toArray();
}
$sorted = usort($transformed, fn($a, $b) => $a['name'] <=> $b['name']);

// BETTER: Single pass + built-in sort
$result = [];
foreach ($items as $item) {
    if ($item->isActive()) {
        $result[] = $item->toArray();
    }
}
usort($result, fn($a, $b) => $a['name'] <=> $b['name']);

3. In-Loop Operations That Could Be Batched

// SLOW: Individual inserts
foreach ($users as $user) {
    $this->repository->save($user);
    $this->em->flush(); // Flush each iteration
}

// FAST: Batch insert
foreach ($users as $user) {
    $this->em->persist($user);
}
$this->em->flush(); // Single flush

// SLOW: Individual API calls
foreach ($items as $item) {
    $this->api->update($item); // HTTP call per item
}

// FAST: Batch API call
$this->api->updateBatch($items);

4. Loop Invariant Code

// INEFFICIENT: Repeated computation
foreach ($items as $item) {
    $config = $this->loadConfig(); // Same result each iteration
    $now = new DateTime(); // Same time each iteration
    $taxRate = $this->getTaxRate($country); // Constant
    process($item, $config, $now, $taxRate);
}

// FIXED: Hoist invariants
$config = $this->loadConfig();
$now = new DateTime();
$taxRate = $this->getTaxRate($country);
foreach ($items as $item) {
    process($item, $config, $now, $taxRate);
}

5. Array Functions vs Loops

// VERBOSE: Manual filter
$active = [];
foreach ($users as $user) {
    if ($user->isActive()) {
        $active[] = $user;
    }
}

// CLEANER: array_filter
$active = array_filter($users, fn($u) => $u->isActive());

// VERBOSE: Manual map
$names = [];
foreach ($users as $user) {
    $names[] = $user->getName();
}

// CLEANER: array_map
$names = array_map(fn($u) => $u->getName(), $users);

// VERBOSE: Manual reduce
$total = 0;
foreach ($orders as $order) {
    $total += $order->getAmount();
}

// CLEANER: array_reduce
$total = array_reduce($orders, fn($sum, $o) => $sum + $o->getAmount(), 0);

6. Early Exit Missing

// INEFFICIENT: Continues after finding
foreach ($users as $user) {
    if ($user->getId() === $targetId) {
        $found = $user;
    }
}

// EFFICIENT: Break when found
foreach ($users as $user) {
    if ($user->getId() === $targetId) {
        $found = $user;
        break;
    }
}

// BETTER: Use array_filter/first or collection method
$found = $collection->first(fn($u) => $u->getId() === $targetId);

7. Counting in Loop

// SLOW: strlen in loop condition
for ($i = 0; $i < strlen($string); $i++) {
    // strlen called each iteration
}

// FAST: Cache length
$len = strlen($string);
for ($i = 0; $i < $len; $i++) {
    // ...
}

// SLOW: count() in loop
for ($i = 0; $i < count($array); $i++) {
    // count called each iteration
}

8. Unnecessary array_merge

// SLOW: array_merge in loop creates new array each time
$result = [];
foreach ($batches as $batch) {
    $result = array_merge($result, $batch);
}

// FAST: Spread operator
$result = array_merge(...$batches);

// FAST: Direct append
$result = [];
foreach ($batches as $batch) {
    foreach ($batch as $item) {
        $result[] = $item;
    }
}

Grep Patterns

# Nested foreach
Grep: "foreach.*foreach" --glob "**/*.php"

# flush() in loop
Grep: "foreach.*->flush\(\)" --glob "**/*.php"

# strlen/count in loop condition
Grep: "for\s*\([^;]+;\s*\$\w+\s*<\s*(strlen|count)\(" --glob "**/*.php"

# array_merge in loop
Grep: "foreach.*array_merge" --glob "**/*.php"

Complexity Comparison

Pattern Before After
Nested loop search O(n*m) O(n+m) with index
Multiple passes O(3n) O(n) single pass
In-loop flush n DB round trips 1 round trip
strlen in condition O(n²) O(n)

Severity Classification

Pattern Severity
Nested loop O(n²) 🔴 Critical
Individual DB operations in loop 🔴 Critical
Loop invariant code 🟠 Major
Multiple array passes 🟠 Major
strlen in condition 🟡 Minor
Verbose vs array_* 🟢 Suggestion

Output Format

### Unnecessary Loop: [Description]

**Severity:** 🔴/🟠/🟡
**Location:** `file.php:line`
**Current Complexity:** O(n²)
**Optimized Complexity:** O(n)

**Issue:**
[Description of the inefficient pattern]

**Code:**
```php
// Inefficient loop

Optimization:

// Optimized version

Improvement: For 1000 items: 1,000,000 ops → 2,000 ops