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 asgetData()? 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 lookupchargeAndNotifyCustomer()has side effects (and theAndis a hint the method is doing too much)fetchPaymentStatus()makes a remote call, so it can be slow or failfindCachedUserData()reads from a cache and may return nothingdeleteOrder()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 intentdata(),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()— theAndusually 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" — clearprocess($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