Naming
Names follow fixed conventions so a name tells you what a thing is and whether it can be null.
Classes are CamelCase. A module's runtime lives on the <Module> class,
and its cross-module configuration lives on a <Module>Config class. A data
object is <Thing>Data and its database class is <Thing>Database.
Anything that can be null is named with an optional prefix, so a name without
optional is always set and needs no null check.
class Member {} // module runtime
class MemberConfig {} // cross-module configuration
class MemberData {} // data object
class MemberDatabase {} // database class
function rename(MemberData $member, ?FolderData $optionalFolder): void {
// $member is always set: use it directly
$name = $member->name;
// $optionalFolder can be null: check before use
if ($optionalFolder !== null) {
$name = $optionalFolder->name . '/' . $name;
}
}
Names carry the module prefix
Every class and every file name starts with the name of the module it is defined in.
In a Shop module you write ShopProduct, ShopProductData,
ShopProductDatabase and ShopPage. The prefix does real work: you can
tell at a glance which module a class belongs to, and names never collide across modules, so
two modules can each have their own product or page class without treading on each other.
class ShopProduct {} // service class
class ShopProductData {} // data object
class ShopProductDatabase {} // database class
class ShopPage {} // page/UI class
Suffixes name the kind of thing
Fixed suffixes tell you what role a class plays. A database class ends in
Database, a data object ends in Data, and a union object
ends in Union. So ShopOrderDatabase talks to the store,
ShopOrderData holds one order's fields, and a ShopPaymentUnion
represents a value that is one of several shapes. See
Objects and types for what a Data class is
allowed to contain.
User-interface function groups end in Ui. A class that builds or renders markup
has a name ending in Ui, such as StatusUi, ChartUi or
MemberAdminPageUi, so you always know where to look when you want UI. See
Module structure and separation for why UI and database
work are grouped this way.
Order names by importance
A name reads left to right from the most important, most general part down to the more
specific. The module comes first, then the thing, then its role or variant. You write
ShopProduct, then ShopProductData and ShopProductDatabase;
you write a table member, then member_auth and
member_folder. The general part is always on the left.
The payoff shows up the moment things are sorted. Because the shared part leads, everything in
the same category or subcategory lands together in an alphabetical list. All of a module's
classes cluster under its prefix, the ShopProduct trio sits as three consecutive
lines, and every member table sorts as one block:
member
member_auth
member_code
member_feature
member_folder
member_password
Scanning becomes reading a grouped list rather than hunting scattered names, and a directory listing or table dump groups itself with no extra effort. The same ordering rule applies to database tables; see Database layer conventions for the table naming details.
The optional prefix
Anything that can be null is named with an optional prefix. A function that may
return null starts its name with optional; a variable that may hold null starts
with optional; a data-object field that may be null starts with optional.
The payoff is that a name without optional is guaranteed to be set, so you
never have to null-check it or wonder whether you should. The name is the contract.
Type such values as TYPE|null, never ?TYPE, so the two possibilities
read left to right and match the wording of the name. See
Database layer conventions for how nullability lines up
with the schema.
// May return null: name and return type both say so.
function optionalCurrentMember(): MemberData|null {
return Member::FromSession();
}
$optionalMember = optionalCurrentMember();
// $product has no optional prefix, so it is always set: use it directly.
$product = ShopProduct::Load($id);
$name = $product->name;
Next: Writing clear code.