craft-php-guidelines

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Craft CMS 5 PHP Guidelines

Craft CMS 5 PHP开发指南

Complete PHP coding standards and conventions for active coding sessions.
适用于日常编码工作的完整PHP编码标准与约定。

Common Pitfalls

常见误区

  • addSelect()
    is the convention in
    beforePrepare()
    — safely additive when multiple extensions contribute columns. Craft's
    **
    placeholder merges defaults regardless, but
    addSelect()
    prevents conflicts.
  • $_instances
    is not a Craft convention — private properties use underscore prefix but meaningful names like
    $_items
    ,
    $_sections
    .
  • Records use the same class name as models (namespace distinguishes). Alias when importing both:
    use ...\records\MyEntity as MyEntityRecord;
    .
  • Queue jobs have no "Job" suffix
    ResaveElements
    , not
    ResaveElementsJob
    .
  • declare(strict_types=1)
    is NOT used in plugin source files. Only in standalone config files like
    ecs.php
    .
  • @author
    goes on classes and methods only — never on properties.
  • Don't use
    string|null
    — use
    ?string
    (short nullable notation).
  • Forget
    parent::defineRules()
    and you lose all inherited validation.
  • DateTimeHelper
    in elements/queries,
    Carbon
    in services — never mix in the same class.
  • Missing
    @throws
    chains — document exceptions from called methods too, not just your own throws.
  • addSelect()
    beforePrepare()
    中的约定用法 — 当多个扩展都需要添加查询字段时可以安全地增量添加。虽然Craft的
    **
    占位符无论如何都会合并默认值,但
    addSelect()
    可以避免冲突。
  • $_instances
    不符合Craft的约定 — 私有属性使用下划线前缀,但要使用有意义的名称,比如
    $_items
    $_sections
  • 记录类(Record)与模型类(Model)使用相同的类名(通过命名空间区分)。同时导入二者时使用别名:
    use ...\records\MyEntity as MyEntityRecord;
  • 队列任务类不带"Job"后缀 — 命名为
    ResaveElements
    ,而非
    ResaveElementsJob
  • 插件源文件中不使用
    declare(strict_types=1)
    ,仅在
    ecs.php
    这类独立配置文件中使用。
  • @author
    仅标注在类和方法上 — 永远不要加在属性上。
  • 不要使用
    string|null
    — 改用
    ?string
    (简短可空类型语法)。
  • 遗漏
    parent::defineRules()
    会导致丢失所有继承来的校验规则。
  • 元素/查询类中使用
    DateTimeHelper
    ,服务类中使用
    Carbon
    — 不要在同一个类中混用二者。
  • 不要遗漏
    @throws
    调用链 — 你调用的方法抛出的异常也要文档化,而不仅仅是你自己代码抛出的异常。

Documentation

参考文档

When unsure about a convention,
web_fetch
the coding guidelines page for the authoritative answer.
如果对某条约定有疑问,使用
web_fetch
获取编码规范页面的权威答案。

Critical Rules

核心规则

  1. PHPDocs on everything: classes, methods, properties. No exceptions.
  2. @throws
    chains: document every exception including uncaught from called methods.
  3. @author
    and
    @since
    at the bottom of class/method docblocks, after a blank line.
  4. Section headers with
    // =========================================================================
    on every class.
  5. declare(strict_types=1)
    is NOT used in plugin source files.
  6. Private methods/properties prefixed with underscore:
    _registerCpUrlRules()
    ,
    $_items
    .
  7. addSelect()
    convention in
    beforePrepare()
    (additive across extensions).
  8. DateTimeHelper
    in elements/queries,
    Carbon
    in services.
  9. Always scaffold with
    ddev craft make <type> --with-docblocks
    , then customize.
  10. ddev composer check-cs
    and
    ddev composer phpstan
    must pass before every commit.
  1. 所有代码都要加PHPDoc:类、方法、属性,没有例外。
  2. @throws
    调用链:所有异常都要文档化,包括调用的方法抛出的未捕获异常。
  3. @author
    @since
    放在类/方法文档块的底部,前面空一行。
  4. 每个类都要用
    // =========================================================================
    添加章节分隔头。
  5. 插件源文件中不使用
    declare(strict_types=1)
  6. 私有方法/属性以下划线为前缀:比如
    _registerCpUrlRules()
    $_items
  7. beforePrepare()
    中约定使用
    addSelect()
    (支持多扩展增量添加字段)。
  8. 元素/查询类中使用
    DateTimeHelper
    ,服务类中使用
    Carbon
  9. 始终使用
    ddev craft make <type> --with-docblocks
    生成基础代码,再进行自定义修改。
  10. 每次提交前必须通过
    ddev composer check-cs
    ddev composer phpstan
    检查。

Section Header Order

章节标题顺序

// Traits
// Const Properties
// Static Properties
// Public Properties
// Protected Properties
// Private Properties
// Public Methods
// Protected Methods
// Private Methods
Only include sections that have content. Blank line after the separator, before the first item.
// Traits
// Const Properties
// Static Properties
// Public Properties
// Protected Properties
// Private Properties
// Public Methods
// Protected Methods
// Private Methods
仅保留有内容的章节。分隔符之后、第一个条目之前空一行。

Naming Quick-Reference

命名速查表

  • Services (resource): Plural —
    Entries
    ,
    Volumes
    ,
    Users
  • Services (utility): Domain noun —
    Auth
    ,
    Search
    ,
    Gc
  • Queue jobs: Action verb, no suffix —
    ResaveElements
    ,
    UpdateSearchIndex
  • Records: Same name as model — namespace distinguishes
  • Events: Three patterns —
    SectionEvent
    ,
    RegisterUrlRulesEvent
    ,
    DefineHtmlEvent
  • Element actions: Action verb, no suffix —
    Delete
    ,
    Duplicate
    ,
    SetStatus
  • Enums: PascalCase cases, string/int backed —
    PropagationMethod
    ,
    CmsEdition
  • 资源类服务:使用复数形式 —
    Entries
    Volumes
    Users
  • 工具类服务:使用领域名词 —
    Auth
    Search
    Gc
  • 队列任务:使用动作动词,无后缀 —
    ResaveElements
    UpdateSearchIndex
  • 记录类:与模型类同名 — 通过命名空间区分
  • 事件类:三种命名模式 —
    SectionEvent
    RegisterUrlRulesEvent
    DefineHtmlEvent
  • 元素动作:使用动作动词,无后缀 —
    Delete
    Duplicate
    SetStatus
  • 枚举类:枚举值使用大驼峰命名,基于字符串/整型 —
    PropagationMethod
    CmsEdition

Verification Checklist

提交前检查清单

Before every commit:
  1. ddev composer check-cs
    passes
  2. ddev composer phpstan
    passes
  3. Tests green
  4. PHPDocs complete on all new/modified code
  5. @throws
    chains verified
  6. Section headers present and correct
  7. Imports alphabetical and grouped
每次提交前:
  1. ddev composer check-cs
    检查通过
  2. ddev composer phpstan
    检查通过
  3. 测试全部通过
  4. 所有新增/修改代码的PHPDoc都已补全
  5. @throws
    调用链已核实
  6. 章节分隔头已添加且格式正确
  7. 导入语句已按字母顺序排序且分组合理