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

A function name should describe the action

Variable names answer "what is this?". Function names answer "what does this do?".

That means a function name almost always starts with a verb, and the verb itself should hint at how the function behaves: is it cheap or expensive, does it return something or change something, can it fail or not.

Picking the right verb saves a thousand "what does this actually do?" questions in code review.

Before

The names tell you almost nothing about what each function actually does.

<?php

class OrderService
{
    public function order(int $orderId): array { /* DB lookup */ }
    public function process(int $orderId): void { /* charges payment + sends email */ }
    public function check(int $orderId): bool { /* calls Stripe API */ }
    public function data(int $userId): array { /* in-memory cache lookup */ }
    public function handle(int $orderId): void { /* deletes the order */ }
}

Every one of these names raises a question:

  • order() — is it creating an order or fetching one?
  • process() — what does "process" actually do? side effects?
  • check() — does it just look something up, or does it call out to a third party?
  • data() — same as getData()? Why the noun?
  • handle() — handle what, exactly? deletes? logs? retries?

After

The verbs do the work. You can read the class and roughly predict what each method costs and whether it changes anything.

<?php

class OrderService
{
    public function getOrder(int $orderId): array { /* DB lookup */ }
    public function chargeAndNotifyCustomer(int $orderId): void { /* charges payment + sends email */ }
    public function fetchPaymentStatus(int $orderId): bool { /* calls Stripe API */ }
    public function findCachedUserData(int $userId): array { /* in-memory cache lookup */ }
    public function deleteOrder(int $orderId): void { /* deletes the order */ }
}

You can now scan the class and immediately know:

  • getOrder() is a cheap local lookup
  • chargeAndNotifyCustomer() has side effects (and the And is a hint the method is doing too much)
  • fetchPaymentStatus() makes a remote call, so it can be slow or fail
  • findCachedUserData() reads from a cache and may return nothing
  • deleteOrder() mutates state and is destructive

Why this version is better

  • the verb tells the reader the kind of work, not just that work happens
  • expensive operations (fetch, query) are visually distinct from cheap ones (get, find)
  • destructive operations (delete, remove, purge) stand out at the call site
  • conjunctions like And (chargeAndNotifyCustomer) become a clear smell that the function does more than one thing

Function verb cheat sheet

Verb Use it for Signals
get a cheap local lookup that always returns a value in-memory or trivial DB read
find a lookup that may return null or empty "might not exist"
fetch a remote or expensive operation network call, slow, can fail
query a database call that may return many rows DB cost, paginated
load reading from disk, cache, or external store I/O cost
create makes a new thing (not yet persisted) constructor-like
make / build assembles a value object or DTO pure, no side effects
save / persist writes to a store side effect, can fail
update changes an existing record side effect, expects the thing to exist
delete / remove destroys data irreversible, double-check at call site
send dispatches something out (email, event, message) I/O + external visibility
calculate / compute derives a value pure, no side effects
is / has / can returns a boolean predicate, see lesson 2.3
to converts between formats (toArray, toJson) pure transformation
process / handle avoid in domain code hides what the function actually does

Names to avoid

  • process(), handle(), manage(), do() — vague verbs that hide intent
  • data(), info(), result() — these are nouns; if a function is named like a noun, the reader expects a property
  • single-letter or abbreviated verbs (gen(), proc(), mgr()) — save nothing, cost clarity
  • getXAndY() — the And usually means the function should be split

A small function smell test

Read the function name as a sentence: "This function will [verb] [thing]."

  • getOrder($id) → "this function will get the order" — clear
  • process($id) → "this function will process the order" — process how?
  • check($id) → "this function will check the order" — check what about it?

If the sentence still leaves a question, the verb is too generic and the name is doing less work than it should.

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