Originally published on decentphp.dev — part of the Writing decent PHP course. View this lesson on the original site.

Abbreviate only when the team genuinely says it out loud

Abbreviations save typing, which is a tiny gain. Bad abbreviations cost reading, which is a much larger loss. The trade only works when the short form is so common that every reader instantly expands it.

The rule of thumb is simple: if you would not say it out loud in a meeting, do not type it in code.

Nobody says "the U.S.R. signed up". They say "the user signed up". So the variable is $user, not $usr.

Everyone says "the H.T.T.P. request". So HttpRequest is fine.

That single test handles 80% of the decisions you have to make in this area.

Before

A function full of saved keystrokes. Every variable looks like a half-typed word.

<?php

function chgSubsForUsrInOrg(array $usr, array $org, array $cfg, $ctx): bool
{
    $sub = $usr['sub'];
    $tx = $cfg['tx_typ'];
    $req = $ctx->req();
    $tmp = $req['amt'] * $cfg['mult'];

    if ($tmp > $org['lim']) {
        return false;
    }

    return $usr['stat'] === 'act';
}

Every reader has to do mental expansion:

  • chg = change? charge? check?
  • Subs = subscriptions? submissions? subscribers?
  • Usr = user (probably)
  • Org = organisation
  • cfg = config
  • ctx = context (Symfony? Laravel? something else?)
  • tx_typ = transaction type, but written like a SQL column
  • tmp = a temporary what?
  • lim = limit (of what?)
  • stat = status, not statistic

The function "saves" maybe twenty keystrokes and costs every reader twenty seconds.

After

The same function with the abbreviations expanded. The only short forms left are universal ones the team would actually say out loud.

<?php

function chargeSubscriptionForUserInOrganisation(
    array $user,
    array $organisation,
    array $billingConfig,
    BillingContext $context
): bool {
    $subscription = $user['subscription'];
    $request = $context->httpRequest();
    $totalInPence = (int) round($request['amount_in_pence'] * $billingConfig['multiplier']);

    if ($totalInPence > $organisation['monthly_limit_in_pence']) {
        return false;
    }

    return $user['status'] === 'active';
}

The function name reads as a sentence. The variables read as words. The only "abbreviation" left (Http) is one nobody ever expands in conversation.

Why this version is better

  • new joiners do not need a private dictionary to read the function
  • search works (grep subscription finds every place subscriptions live; grep sub finds chaos)
  • the function name itself is now a one-line description of what it does
  • review comments can talk about the rule (monthly_limit_in_pence) instead of asking "what is lim?"

Abbreviations that earn their keep

Acronym Why it survives How to write it in PHP
HTTP, HTTPS said as letters; universal HttpRequest, HttpsClient
URL, URI spoken as letters $signupUrl, UriParser
JSON, XML, CSV, HTML, CSS, PDF said as letters or pronounced as one syllable JsonEncoder, HtmlRenderer
SQL universal in any DB code SqlQueryBuilder
API, SDK universal StripeApiClient
UUID, ID universal $userId, $invoiceUuid
IO systems-level convention IoException
DB acceptable in DB-only contexts $dbConnection is fine; $dbStuff is not
OS, CPU, RAM universal hardware terms OsVersion, CpuUsage

Note the casing: when an acronym is used as part of a class or variable name, treat it as a normal word (HttpRequest, not HTTPRequest). This is the PSR convention and it keeps multi-word names readable (XmlHttpRequest, not XMLHTTPRequest).

Abbreviations that almost never earn their keep

Bad Why it fails Better
usr nobody says "U.S.R." user
req could mean request, requirement, requeue request, requirement
res request? response? result? reservation? response, result
cfg, conf universal concept, not a universal abbreviation config
ctx leaks framework jargon into business code context, or name the specific context
tmp, temp hides what kind of "temporary" name the actual value
mgr, mngr "manager" was already vague (lesson 2.6) — abbreviating doubles the problem rename the class
lst, arr, obj, dict, var type-shape names (lesson 2.1) wearing a disguise name by intent
stat status or statistic? status, statistic
loc, qty, addr save 3 characters, cost a translation location, quantity, address
Domain-specific 3-letter codes (pmt, inv, cst) only readable to the original author payment, invoice, customer

Team-specific acronyms

Most teams have one or two of these — KYC, MRR, LTV, SLA, PII, an internal product code. They are fine in code if they pass two tests:

  1. Anyone with onboarding completed knows what it means.
  2. It is in the repo glossary (see lesson 2.8).

If a team-specific acronym fails either test, expand it in code and add it to the glossary the first time it appears.

Single-letter names

Single letters are fine in two narrow cases:

  • a tight, obvious loop counter — for ($i = 0; $i < $n; $i++)
  • a closure parameter where the meaning is obvious from one line above — array_filter($users, fn ($u) => $u['active']) is acceptable; fn ($user) => $user['active'] is better

Outside those, single letters cost more than they save. $x, $y, $d, $n in business logic are almost always a missed naming opportunity.

A small abbreviation smell test

For every short name in your code, ask:

  1. Would I say this exact short form out loud in a stand-up?
  2. Could it expand into more than one English word?
  3. Would a new joiner need to ask what it means?

If the answer to (1) is no, or to (2) or (3) is yes, expand the name. The few extra characters are the cheapest part of the entire system.

From Writing decent PHP — Naming variables, functions, classes, and files well