A component is a small, self-contained piece of code that does one job and can be used in many places: a validator, a logger, a pagination calculator, a card template.
Reusable components share a few traits.
1. One job
A class named Paginator should paginate. If it also sends email, it is not reusable.
<?php
final class Paginator
{
public function __construct(
private int $total,
private int $perPage,
private int $page,
) {
$this->page = max(1, min($page, $this->pages()));
}
public function pages(): int
{
return max(1, (int) ceil($this->total / $this->perPage));
}
public function offset(): int
{
return ($this->page - 1) * $this->perPage;
}
public function page(): int
{
return $this->page;
}
}
$p = new Paginator(total: 47, perPage: 10, page: 3);
echo "page {$p->page()} of {$p->pages()}, offset {$p->offset()}";
page 3 of 5, offset 20
It knows nothing about databases, URLs or HTML. Any page can use it.
2. Dependencies come in through the constructor
A component should not create its own tools. It asks for them. See Dependency Injection.
3. A clear, small public interface
Few public methods, clear names, typed parameters, and exceptions for misuse.
4. No hidden state or output
A reusable function returns a value. It does not echo, read $_GET or write to a global.
<?php
// Hard to reuse: reads and prints
function showGreetingBad(): void
{
echo "Hello, " . ($_GET["name"] ?? "guest");
}
// Reusable: input in, value out
function greeting(string $name): string
{
return "Hello, " . ($name !== "" ? $name : "guest");
}
echo greeting("Ana") . " / " . greeting("");
Hello, Ana / Hello, guest
Template components
A card, a button, a form field: keep the HTML in a partial and pass data in.
<article class="card">
<h2><?= htmlspecialchars($title) ?></h2>
<p><?= htmlspecialchars($text) ?></p>
</article>
<?php
function partial(string $file, array $data = []): string
{
extract($data, EXTR_SKIP); // $title and $text become local variables
ob_start();
include $file;
return ob_get_clean();
}
file_put_contents("card.php", '<article class="card"><h2><?= htmlspecialchars($title) ?></h2><p><?= htmlspecialchars($text) ?></p></article>');
echo partial(__DIR__ . "/card.php", ["title" => "Tom & Jerry", "text" => "A <classic> cartoon"]);
<article class="card"><h2>Tom & Jerry</h2><p>A <classic> cartoon</p></article>
How it works: extract() turns array keys into variables, ob_start() captures output, and ob_get_clean() returns it as a string. EXTR_SKIP stops the data from overwriting existing variables.
Value objects
Small immutable objects make good components: Money, Email, DateRange, Slug. They validate themselves once, and every user of the object can trust it. See Encapsulation.
Where to keep them
src/
├── Support/ small helpers and value objects
├── Service/ business logic
├── Repository/ database access
└── View/ template helpers
templates/
└── partials/ card.php, form-field.php
Reuse without over-engineering
- Wait until you need something three times, then extract it.
- Do not add options “just in case”. A component with twelve parameters is hard to use.
- Prefer composition over a deep class tree (see Composition vs Inheritance).
- Use well-maintained Composer packages for solved problems (mail, Markdown, dates, HTTP) instead of writing your own.
Test your components
A component with no hidden dependencies is easy to test with a few lines. That is a good sign of a good design.
Why this matters in WordPress and Laravel
get_template_part()) and Laravel has Blade components. Both are the partial idea above with more features.