← Home ← Codex ← DEBT
Browse by Category
+ added · updated 7d
← Back to glossary

Topological Sort

Algorithms PHP 7.4+ Intermediate
debt(d9/e5/b5/t7)
d9 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'silent in production until users hit it' (d9). The detection_hints field explicitly states automated: no, and the code_pattern describes nested loops and repeated array_diff/in_array — patterns that produce no compiler or linter warnings. A cycle in the dependency graph silently returns a partial ordering, and this only manifests when users encounter broken dependency resolution at runtime. No tools from detection_hints.tools (list is empty) can catch this automatically.

e5 Effort Remediation debt — work required to fix once spotted

Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix says to use Kahn's algorithm with an in-degree map and queue, but this isn't a one-line swap — it requires replacing ad-hoc nested loop logic, adding cycle detection, and ensuring callers handle the error/exception when a cycle is found. This likely touches the dependency resolver component and its consumers, making it a meaningful refactor within one component or across a few related ones.

b5 Burden Structural debt — long-term weight of choosing wrong

Closest to 'persistent productivity tax' (b5). The applies_to covers both web and cli contexts broadly. Any system doing dependency resolution, build ordering, or migration ordering will have this algorithm at its core. A naive or incorrect implementation (missing cycle detection, non-linear complexity) imposes an ongoing tax: tests can't rely on output order, edge cases around cycles require workarounds, and performance degrades on large graphs — slowing down multiple work streams without fully defining the system's architecture.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap (contradicts how a similar concept works elsewhere)' (t7). The misconception field states that developers assume topological sort works on any directed graph, when it only works on DAGs. This contradicts the intuition from general sorting (which always produces a result) and from directed-graph traversal (which succeeds on cyclic graphs). Additionally, common_mistakes highlight that silent partial ordering on cycles, assuming unique output, and using it on undirected graphs are all serious pitfalls — multiple traps that competent developers regularly fall into.

About DEBT scoring →

Also Known As

topo sort dependency ordering DAG ordering

TL;DR

An ordering of nodes in a directed acyclic graph (DAG) such that for every directed edge u→v, node u appears before v in the ordering.

Explanation

Topological sort is only possible on directed acyclic graphs (DAGs) — any cycle makes a valid ordering impossible. Two common algorithms: Kahn's algorithm uses in-degree counts and a queue (BFS-based), and DFS-based sort uses recursive post-order traversal. Both run in O(V + E). The result is not unique — many valid orderings may exist. Real-world applications are everywhere: package/dependency managers (Composer, npm) use it to determine installation order, build systems (Make, Gradle) use it for task scheduling, course prerequisite systems, and database migration runners rely on it to apply schema changes in the right order.

Diagram

flowchart LR
    subgraph DAG Input
        A --> B
        A --> C
        B --> D
        C --> D
        D --> E
    end
    subgraph Kahn Step-by-Step
        K1[Start: A has in-degree 0] --> K2[Process A<br/>reduce B and C]
        K2 --> K3[Process B and C<br/>reduce D]
        K3 --> K4[Process D<br/>reduce E]
        K4 --> K5[Process E<br/>done]
    end
    RESULT[Order: A - B - C - D - E]
style RESULT fill:#238636,color:#fff
style K1 fill:#1f6feb,color:#fff

Common Misconception

Topological sort works on any directed graph — it only works on DAGs. If a cycle exists (A→B→C→A) there is no valid topological ordering, and Kahn's algorithm will detect this because not all nodes will be processed (remaining in-degrees never reach zero).

Why It Matters

Any time you have tasks, packages, or migrations with dependencies, you need topological sort under the hood. Implementing a dependency resolver or build system without understanding it leads to brittle ad-hoc ordering logic that breaks on edge cases.

Common Mistakes

  • Not detecting cycles — silently returning a partial ordering when a cycle exists instead of throwing an error.
  • Using topological sort on an undirected graph — the concept only applies to directed edges.
  • Assuming the output order is unique — many valid orderings exist; tests should not depend on a specific one.
  • Reinventing it manually with nested loops instead of using Kahn's or DFS — O(V²) instead of O(V+E).

Code Examples

💡 Note
Kahn's naturally detects cycles — if `count($order) !== count($graph)` after processing, a cycle prevented some nodes from ever reaching in-degree zero.
✗ Vulnerable
// Naive: repeatedly scan for nodes with no unresolved deps — O(V²):
function topoNaive(array $deps): array {
    $resolved = [];
    while (count($resolved) < count($deps)) {
        $progress = false;
        foreach ($deps as $node => $nodeDeps) {
            if (!in_array($node, $resolved) &&
                empty(array_diff($nodeDeps, $resolved))) {
                $resolved[] = $node;
                $progress = true;
            }
        }
        if (!$progress) throw new RuntimeException('Cycle detected');
    }
    return $resolved;
}
✓ Fixed
// Kahn's algorithm — O(V+E) with cycle detection:
function topologicalSort(array $graph): array {
    $inDegree = array_fill_keys(array_keys($graph), 0);
    foreach ($graph as $neighbours) {
        foreach ($neighbours as $v) $inDegree[$v]++;
    }
    $queue = array_keys(array_filter($inDegree, fn($d) => $d === 0));
    $order = [];
    while ($queue) {
        $u = array_shift($queue);
        $order[] = $u;
        foreach ($graph[$u] as $v) {
            if (--$inDegree[$v] === 0) $queue[] = $v;
        }
    }
    if (count($order) !== count($graph)) {
        throw new RuntimeException('Graph has a cycle — topological sort impossible');
    }
    return $order;
}

// Usage: ['a' => ['b','c'], 'b' => ['d'], 'c' => ['d'], 'd' => []]
// Returns: ['a', 'b', 'c', 'd'] or ['a', 'c', 'b', 'd']

Added 24 Mar 2026
Views 52
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 0 pings W 1 ping T 0 pings F 0 pings S 0 pings S 0 pings M 1 ping T 0 pings W 0 pings T 0 pings F 1 ping S 2 pings S 0 pings M 0 pings T 0 pings W 1 ping T 1 ping F 0 pings S 0 pings S 0 pings M 1 ping T 0 pings W 0 pings T 0 pings F 0 pings S 3 pings S 1 ping M 1 ping T 0 pings W
No pings yet today
SEMrush 1
Amazonbot 10 Google 6 Perplexity 5 Ahrefs 4 ChatGPT 3 Scrapy 3 PetalBot 3 Unknown AI 2 Claude 2 Meta AI 1 Bing 1 SEMrush 1
crawler 38 crawler_json 3
DEV INTEL Tools & Severity
🟢 Low ⚙ Fix effort: Medium
⚡ Quick Fix
Use Kahn's algorithm with an in-degree map and queue — O(V+E), detects cycles automatically
📦 Applies To
PHP 7.4+ web cli
🔗 Prerequisites
🔍 Detection Hints
Nested loops resolving dependency order; repeated array_diff or in_array inside while loop
Auto-detectable: ✗ No
⚠ Related Problems
🤖 AI Agent
Confidence: Medium False Positives: Medium ✗ Manual fix Fix: Medium Context: Function Tests: Update


✓ schema.org compliant