RSS Amplifier

jpslvtr.substack.com · Jul 19, 2025

Why I still like PHP

0
Sign in to vote or save

JP Salvatore · jpslvtr.substack.com

PHP is a programming language that has fallen out of favor for a variety of reasons. It’s “old,” it historically lacked safe defaults, and it has unique syntax. But the main reason I think it’s often dismissed is a variation of “old”: modern alternatives for server-side code, like Node.js, are far more popular. Why they are more popular is something I will explain.

PHP has a special place in my heart because it’s the first programming language I learned that allowed me to create dynamic websites. While I won’t argue that PHP is better than Node.js, Python, or Go for deploying websites today, I will argue that it is still a great programming language and one worth learning. In particular, I am going to explain 1. why PHP is important, 2. why it’s less popular today, and 3. why we should use it more today.

I first learned PHP in 2015 when I took an undergrad class called Web & Internet Programming. Before that, when it came to websites, I only knew basic HTML and how to build static pages. This class taught the fundamentals of building full-stack web applications: JavaScript for client-side interactivity, manipulating the DOM, AJAX, and server-side scripting with PHP. We were taught PHP because it was the simplest way to teach us a fundamental truth about the web: client code runs in the browser; server code runs before the page is sent. PHP embeds directly inside HTML, which makes the execution boundary explicit:

<?php echo “This runs on the server”; ?>

PHP introduces state, which the web does not give you for free. HTTP is stateless, meaning each request is independent and the server forgets everything once a response is sent unless you explicitly persist information across requests. PHP exposes request data through global variables like $_GET and $_POST, making explicit what arrives with a single request and what disappears immediately afterward. $_GET contains parameters appended to the URL after a ?. For example, given this request:

GET /search.php?q=oranges&page=2

PHP sees:

$_GET[’q’]    // “oranges”
$_GET[’page’] // “2”

$_POST contains data sent in the request body. Unlike $_GET, these parameters are not visible in the URL. Cookies and sessions build on this by turning transient request data into state that persists across requests. Together, PHP’s insistence on making request boundaries and persistence explicit forces you to confront questions like: How does a server remember a user? Why does refreshing a page lose data? Where does authentication live?

In the 2000s, PHP dominated the web. It powered, and still powers, WordPress and Wikipedia. Mark Zuckerberg wrote early Facebook entirely in PHP and MySQL. Facebook later moved to Hack, a PHP-derived language created at Facebook, which still powers much of Meta’s backend infrastructure today.

At the time, almost everyone used the same LAMP stack: Linux, Apache, MySQL, and PHP. LAMP was cheap, simple, and everywhere. But the web changed.

The web’s dominant architecture shifted in the early 2010s. Early web applications worked like this: the browser requested a page, the server rendered HTML, and the browser displayed it. PHP excels at generating HTML in response to a request. That model held as long as every meaningful interaction required a full page reload.

<h1>Search results for <?php echo $_GET[’q’]; ?></h1>

AJAX, short for Asynchronous JavaScript and XML, was the inflection point. It allowed the browser to make HTTP requests to a server without reloading the page. Before AJAX, forms were submitted, PHP rendered new HTML, and the browser replaced the entire document. Once AJAX became common, the model inverted. Instead of returning complete HTML documents, servers increasingly returned structured data. The browser became responsible for rendering UI state, and the server became a data provider rather than a page generator. This shift made JSON APIs the dominant contract between client and server.

In modern web applications, the server exposes data, and the client renders the interface dynamically:

// server
app.get("/api/search", (req, res) => {
  res.json({ query: req.query.q, results });
});
// client
fetch("/api/search?q=oranges")
  .then(res => res.json())
  .then(data => renderResults(data));

Once APIs became the primary interface between client and server, the question became which language was best positioned to live on both sides of that boundary. PHP could serve JSON just fine. But it was designed around rendering HTML, not around acting as a long-running API server coordinating many asynchronous requests. JavaScript, on the other hand, was already running in the browser. When Node.js made JavaScript viable on the server, the incentives aligned. You could use one language end to end, share data models and validation logic, and reduce context switching between frontend and backend:

// shared validation logic
export function validateUser(user) {
  return user.email && user.password;
}

That convenience mattered more to teams than pedagogical clarity. The abstraction was leaky, but the market won. PHP, by contrast, remained deliberately server-only. PHP makes data flow explicit through HTML forms:

<form method="POST" action="login.php">
  <input name="username">
  <input name="password" type="password">
  <button type="submit">Login</button>
</form>
// login.php
$username = $_POST['username'];
$password = $_POST['password'];

You can see exactly how data leaves the browser, how it arrives at the server, and which HTTP method is used. Modern applications still perform the same operations, but the request body is parsed for you, routing is abstracted, and middleware handles most of the plumbing:

fetch("/api/login", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ username, password })
});
// server
app.post("/api/login", (req, res) => {
  const { username, password } = req.body;
});

The mechanics still exist, but they are hidden behind middleware and conventions. The boundary is less visible.

At minimum, PHP should be everyone’s introduction to server-side programming. If you start with JavaScript-based server stacks (which I’ll abbreviate JBSS), you miss boundaries that must be fully understood before building more complex systems. These stacks often hide the client–server boundary; PHP makes execution context obvious. PHP runs, produces HTML, and disappears. JavaScript runs later, in the browser.

With Node.js, you might write:

app.get("/", (req, res) => {
  res.render("index", { user });
});

Everything is in JavaScript. You’re not forced to ask where the code is running, when it executes, or what exists at that moment. With JBSS, rendering may happen on the server, the edge, the client, or all three depending on configuration. It is often unclear what the browser actually receives.

Frameworks like Next.js replace explicit mechanics such as HTTP handling, routing, request lifecycles, and sessions with abstraction. You miss out on learning how headers are parsed, how request bodies are read, why sessions exist, and why cookies are insecure by default.

JBSS also encourages premature async thinking. In Node.js, developers are introduced early to callbacks, promises, async and await, and event loops. These are powerful concepts, but they are layered on top of HTML and HTTP. It is a lot for a beginner to juggle concurrency and nonblocking I/O before understanding the request–response lifecycle and statelessness.

The runtime illusion is especially dangerous. In Node.js, the server is a long-lived process. Beginners can start to believe memory should persist across requests. PHP resets state on every request by default. This teaches the correct mental model: the server remembers nothing unless you explicitly make it remember. That distinction is fundamental to both security and scalability.

Relying exclusively on JBSS also has longer-term consequences for the web ecosystem. When an entire generation of developers learns the web through frameworks that blur execution context and abstract away HTTP and state, those fundamentals erode at the ecosystem level. The result is software that works when frameworks behave, but fails when they don’t.

PHP’s value is that it preserves a clear mental model of how the web works. Most of the web still runs on request–response cycles, server-side rendering, cookies, sessions, and form submissions. JBSS evolved in response to pressures such as richer interfaces and faster development cycles. In doing so, they accumulated layers of abstraction that prioritize flexibility and convenience. PHP, by contrast, remained largely insulated from those pressures. As a result, it preserved the conceptual clarity of HTTP and the browser–server distinction. JBSS also blurs trust boundaries. When everything is written in JavaScript, code from the browser can appear no different from code on the server. PHP reinforces an important rule: anything coming from the browser should be treated as hostile.

PHP teaches you to reason about software from first principles. If you ignore PHP, you risk confusing execution context, misunderstanding state, over-trusting frameworks, and struggling when debugging real systems.

No posts

Read the original on jpslvtr.substack.com

Comments

Nothing yet. Say the first thing.

    Sign in to join the conversation.