PHP编码标准

这些 PHP 编码标准适用于整个 WordPress 社区。它们对于 WordPress Core 是强制性的,我们鼓励您也将它们用于您的主题和插件。

虽然主题和插件可能会选择遵循不同的编码风格,但这些编码标准不仅与代码风格有关,还包含 WordPress 生态系统中有关互操作性、可翻译性和安全性的既定最佳实践,因此,即使使用不同的代码风格,我们建议您仍然遵守有关这些最佳实践的 WordPress 编码标准。

虽然并非所有代码(目前)都完全符合这些标准,但所有新提交和/或更新的代码都应该完全符合这些编码标准。

另请参阅PHP内联文档标准以获取更多指南。

如果你想根据这个标准自动检查你的代码,你可以使用官方的WordPress 编码标准工具,它使用PHP_CodeSniffer运行。

通用标准

打开和关闭 PHP 标签

在 HTML 块中嵌入多行 PHP 片段时,PHP 开始和结束标记必须单独在一行上。

正确(多行):

<?php
function foo() {
?>
    <div>
    <?php
        echo esc_html(
            bar(
                $baz,
                $bat
            )
        );
        ?>
    </div>
    <?php
}```

正确(单行):

```php
<input name="<?php echo esc_attr( $name ); ?>" />

错误:

if ( $a === $b ) { ?>
<some html>
<?php }

没有速记 PHP 标签

重要提示切勿使用速记 PHP 开始标记。始终使用完整的 PHP 标记。

正确:

<?php ... ?>
<?php echo esc_html( $var ); ?>

错误:

<? ... ?>
<?= esc_html( $var ) ?>

单引号和双引号

适当时使用单引号和双引号。如果您不评估字符串中的任何内容,请使用单引号。你应该几乎永远不必转义字符串中的引号,因为你可以改变你的引用风格,像这样:

echo '<a href="/static/link" class="button button-primary">Link name</a>';
echo "<a href='{$escaped_link}'>text with a ' single quote</a>";

进入 HTML 或 XML 属性的文本应该被转义,这样单引号或双引号就不会结束属性值并使 HTML 无效,从而导致安全问题。有关详细信息,请参阅插件手册中的数据验证。

编写 include/require 语句

因为include[_once]require[_once]是语言结构,它们不需要在路径周围加括号,所以不应该使用它们。路径和 include/require 关键字之间应该只有一个空格。

_强烈建议_用于无条件require[_once]包含。使用 时include[_once],PHP 会在找不到文件但会继续执行时抛出警告,如果您的应用程序依赖于加载的文件,这几乎肯定会导致抛出其他错误/警告/通知,从而可能导致安全漏洞。出于这个原因,require[_once]通常是更好的选择,因为Fatal Error如果找不到文件,它会抛出一个错误。

// Correct.
require_once ABSPATH . 'file-name.php';

// Incorrect.
include_once  ( ABSPATH . 'file-name.php' );
require_once     __DIR__ . '/file-name.php';

命名

命名约定

在变量、动作/过滤器和函数名称中使用小写字母(从不camelCase)。通过下划线分隔单词。不要不必要地缩写变量名;让代码明确且自我记录。

function some_name( $some_variable ) {}

对于函数参数名称,_强烈建议_避免保留关键字作为名称,因为这会导致在使用 PHP 8.0“函数调用中的命名参数”功能时难以阅读和混淆代码。
另请记住,自 PHP 8.0 以来,重命名函数参数应被视为重大更改,因此请谨慎命名函数参数!

Class、trait、interface 和 enum 名称应该使用下划线分隔的大写单词。任何首字母缩略词都应全部大写。

class Walker_Category extends Walker {}
class WP_HTTP {}

interface Mailer_Interface {}
trait Forbid_Dynamic_Properties {}
enum Post_Status {}

常量应全部大写,并用下划线分隔单词:

define( 'DOING_AJAX', true );

文件应使用小写字母进行描述性命名。连字符应该分隔单词。

my-plugin-name.php

类文件名应以类名为准class-,将类名中的下划线替换为连字符,例如WP_Error变为:

class-wp-error.php

此文件命名标准适用于所有包含类的当前文件和新文件,测试类除外。
对于包含测试类的文件,根据 PSR4,文件名应准确反映类名。这是为了确保与所有受支持的 PHPUnit 版本的跨版本兼容性。

目录中包含模板标签的文件wp-includes应该-template附加到名称的末尾,这样它们就很明显了。

general-template.php

命名动态钩子的插值

出于可读性和可发现性目的,动态钩子应该使用插值而不是连接来命名。

动态钩子是在其标签名称中包含动态值的钩子,例如{$new_status}_{$post->post_type}(publish_post)。

{钩子标签中使用的变量应该用花括号和括起来},完整的外部标签名称用双引号括起来。这是为了确保 PHP 可以正确解析内插字符串中给定变量的类型。

do_action( "{$new_status}_{$post->post_type}", $post->ID, $post );

在可能的情况下,标签名称中的动态值也应尽可能简洁明了。$user_id比 . 更能自我记录$this->id

空格

空间使用

始终在逗号之后以及逻辑运算符、算术运算符、比较运算符、字符串运算符和赋值运算符的两侧放置空格。

SOME_CONST === 23;
foo() && bar();
! $foo;
array( 1, 2, 3 );
$baz . '-5';
$term .= 'X';
if ( $object instanceof Post_Type_Interface ) {}
$result = 2 ** 3; // 8.

在控制结构块的左括号和右括号的两边放置空格。

foreach ( $foo as $bar ) { ...

定义函数时,这样做:

function my_function( $param1 = 'foo', $param2 = 'bar' ) { ...

function my_other_function() { ...

调用函数时,这样做:

my_function( $param1, func_param( $param2 ) );
my_other_function();

执行逻辑比较时,这样做:

if ( ! $foo ) { ...

类型转换必须是小写的。总是喜欢简短形式的类型转换,(int)而不是(integer)and(bool)而不是(boolean). 对于 float casts 使用(float), not (real)which 在 PHP 7.4 中被弃用,并在 PHP 8 中被移除:

foreach ( (array) $foo as $bar ) { ...

$foo = (bool) $bar;

引用数组项时,如果它是变量,则仅在索引周围包含一个空格,例如:

$x = $foo['bar']; // Correct.
$x = $foo[ 'bar' ]; // Incorrect.

$x = $foo[0]; // Correct.
$x = $foo[ 0 ]; // Incorrect.

$x = $foo[ $bar ]; // Correct.
$x = $foo[$bar]; // Incorrect.

在块中,条件和冒号switch之间不能有空格。case

switch ( $foo ) {
    case 'bar': // Correct.
    case 'ba' : // Incorrect.
}

除非另有说明,否则括号内应有空格。

if ( $foo && ( $bar || $baz ) ) { ...

my_function( ( $x - 1 ) * 5, $y );

使用递增 ( ++) 或递减 ( --) 运算符时,运算符和它所应用的变量之间不应有空格。

// Correct.
for ( $i = 0; $i < 10; $i++ ) {}

// Incorrect.
for ( $i = 0; $i < 10; $i ++ ) {}
++   $b; // Multiple spaces.

缩进

您的缩进应始终反映逻辑结构。使用真正的 tabs而不是 spaces,因为这样可以在客户端之间实现最大的灵活性。

例外:如果你有一段代码,如果对齐的话会更具可读性,请使用空格:

[tab]$foo   = 'somevalue';
[tab]$foo2  = 'somevalue2';
[tab]$foo34 = 'somevalue3';
[tab]$foo5  = 'somevalue4';

对于关联数组,当数组包含多个项目时,每个项目都应另起一行:

$query = new WP_Query( array( 'ID' => 123 ) );
$args = array(
[tab]'post_type'   => 'page',
[tab]'post_author' => 123,
[tab]'post_status' => 'publish',
);

$query = new WP_Query( $args );

请注意最后一个数组项之后的逗号:这是推荐的,因为它可以更轻松地更改数组的顺序,并在添加新项时使差异更清晰。

$my_array = array(
[tab]'foo'   => 'somevalue',
[tab]'foo2'  => 'somevalue2',
[tab]'foo3'  => 'somevalue3',
[tab]'foo34' => 'somevalue3',
);

对于switch控制结构,case语句应从语句缩进一个switch制表符,而内容case应从条件语句缩进一个制表符case

switch ( $type ) {
[tab]case 'foo':
[tab][tab]some_function();
[tab][tab]break;
[tab]case 'bar':
[tab][tab]some_function();
[tab][tab]break;
}

经验法则:制表符应用于行首以进行缩进,而空格可用于行中对齐。

删除尾随空格

删除每行末尾的尾随空格。最好省略文件末尾的结束 PHP 标记。如果您使用标签,请确保删除尾随空格。

函数体末尾不应有尾随空行。

格式化

大括号样式

此处显示的样式中的所有块都应使用大括号:

if ( condition ) {
    action1();
    action2();
} elseif ( condition2 && condition3 ) {
    action3();
    action4();
} else {
    defaultaction();
}

如果您有一个非常长的块,请考虑是否可以将它分成两个或更多个较短的块、函数或方法,以降低复杂性、提高测试的便利性并增加可读性。

应始终使用大括号,即使在不需要时也是如此:

if ( condition ) {
    action0();
}

if ( condition ) {
    action1();
} elseif ( condition2 ) {
    action2a();
    action2b();
}

foreach ( $items as $item ) {
    process_item( $item );
}

请注意,要求使用大括号意味着禁止使用_单语句内联控制结构。_您可以自由使用控制结构的替代语法(例如if/ endifwhile/ endwhile)——尤其是在 PHP 代码嵌入到 HTML 中的模板中,例如:

<?php if ( have_posts() ) : ?>
    <div class="hfeed">
        <?php while ( have_posts() ) : the_post(); ?>
            <article id="<?php echo esc_attr( 'post-' . get_the_ID() ); ?>" class="<?php echo esc_attr( get_post_class() ); ?>">
                <!-- ... -->
            </article>
        <?php endwhile; ?>
    </div>
<?php endif; ?>

声明数组

使用长数组语法 ( array( 1, 2, 3 )) 声明数组通常比短数组语法 ( [ 1, 2, 3 ]) 更具可读性,特别是对于那些有视力障碍的人。此外,它对初学者更具描述性。

必须使用长数组语法声明数组。

多行函数调用

将函数调用拆分为多行时,每个参数必须在单独的行中。单行内联注释可以占自己一行。

每个参数不得超过一行。必须将多行参数值分配给一个变量,然后将该变量传递给函数调用。

$bar = array(
    'use_this' => true,
    'meta_key' => 'field_name',
);
$baz = sprintf(
    /* translators: %s: Friend's name */
    __( 'Hello, %s!', 'yourtextdomain' ),
    $friend_name
);

$a = foo(
    $bar,
    $baz,
    /* translators: %s: cat */
    sprintf( __( 'The best pet is a %s.' ), 'cat' )
);

类型声明

类型声明必须在类型前后各留一个空格。可空性运算符 ( ?) 被视为类型声明的一部分,此运算符与实际类型之间不应有空格。基于类/接口/枚举名称的类型声明应使用声明的类/接口/枚举名称的大小写,而基于关键字的类型声明应小写。

返回类型声明在函数声明的右括号和开始返回类型的冒号之间不应有空格。

这些规则适用于所有允许类型声明的结构:函数、闭包、枚举、catch 条件以及 PHP 7.4 箭头函数和类型化属性。

// Correct.
function foo( Class_Name $parameter, callable $callable, int $number_of_things = 0 ) {
    // Do something.
}

function bar(
    Interface_Name&Concrete_Class $param_a,
    string|int $param_b,
    callable $param_c = 'default_callable'
): User|false {
    // Do something.
}

// Incorrect.
function baz(Class_Name $param_a, String$param_b,      CALLABLE     $param_c )   :   ?   iterable   {
    // Do something.
}

### 笔记:

根据应用程序所需的最低 PHP 版本,无论是 WordPress 核心、插件还是主题,类型声明的使用有以下限制:

  • 在最低 PHP 版本为 PHP 7.0 或更高版本之前,不能使用标量、bool、和类型声明。int``float``string
  • 在最低 PHP 版本为 PHP 7.0 或更高版本之前,不能使用返回类型声明。
  • 在最低 PHP 版本为 PHP 7.1 或更高版本之前,不能使用可空类型声明。
  • 在最低 PHP 版本为 PHP 7.1 或更高版本之前,不能使用iterable和类型声明。voidvoid类型只能用作返回类型。
  • object在最低 PHP 版本为 PHP 7.2 或更高版本之前,无法使用类型声明。
  • 在最低 PHP 版本为 PHP 7.4 或更高版本之前,不能使用属性类型声明。
  • static(仅返回类型)在最低 PHP 版本为 PHP 8.0 或更高版本之前不能使用。
  • mixed在最低 PHP 版本为 PHP 8.0 或更高版本之前,不能使用类型。请注意,该mixed类型包括null,因此不能为空。
  • 在最低 PHP 版本为 PHP 8.0 或更高版本之前,无法使用联合类型。
  • 在最低 PHP 版本为 PHP 8.1 或更高版本之前,不能使用交集类型。
  • never(仅返回类型)在最低 PHP 版本为 PHP 8.1 或更高版本之前不能使用。
  • 在最低 PHP 版本为 PHP 8.2 或更高版本之前,不能使用析取范式类型(结合联合类型和交集类型)。

警告:

向现有的 WordPress 核心函数添加类型声明应该格外小心。

任何可以被插件或主题重载的函数(方法)的函数签名都不应该被触及。
现在,这只剩下全局命名空间中无条件声明的函数、private类方法和 Core 新代码,作为添加类型声明的候选者。

注意:目前强烈建议array不要在类型声明中使用关键字,因为大多数情况下,最好使用它以在实现中提供更大的灵活性,并且在提高最低要求之前,该关键字尚不能用于 WordPress 核心到 PHP 7.1。iterable

魔法常量

PHP原生的__*__魔术常量,如__CLASS____DIR__,在使用时应大写。

使用::class常量进行类名解析时,class关键字应小写,::运算符两边不能有空格。

// Correct.
add_action( 'action_name', array( __CLASS__, 'method_name' ) );
add_action( 'action_name', array( My_Class::class, 'method_name' ) );

// Incorrect.
require_once __dIr__ . '/relative-path/file-name.php';
add_action( 'action_name', array( My_Class :: CLASS, 'method_name' ) );

传播算子...

使用展开运算符时,展开运算符前应有一个空格或换行并适当缩进。扩展运算符和它适用的变量/函数调用之间不应有空格。将扩展运算符与引用运算符&结合使用时,它们之间不应有空格。

// Correct.
function foo( &...$spread ) {
    bar( ...$spread );

    bar(
        array( ...$foo ),
        ...array_values( $keyed_array )
    );
}

// Incorrect.
function fool( &   ... $spread ) {
    bar(...
             $spread );

    bar(
        [...  $foo ],... array_values( $keyed_array )
    );
}

笔记:

自 PHP 5.6 起,展开运算符(或在其他语言中称为 splat 运算符)可用于在函数声明(可变参数函数)中打包参数并在函数调用中解包它们。自 PHP 7.4 起,展开运算符也用于解包数字索引数组,自 PHP 8.1 起可用字符串键控数组解包。
在函数声明中使用时,扩展运算符只能与最后一个参数一起使用。

声明语句、命名空间和导入语句

命名空间声明

命名空间名称的每个部分都应该由下划线分隔的大写单词组成。

命名空间声明在声明之前应该只有一个空行,在声明之后至少有一个空行。

namespace Prefix\Admin\Domain_URL\Sub_Domain\Event; // Correct.

每个文件应该只有一个名称空间声明,并且它应该位于文件的顶部。不允许使用花括号语法的命名空间声明。显式全局命名空间声明(没有名称的命名空间声明)也是不允许的。

// Incorrect: namespace declaration using curly brace syntax.
namespace Foo {
    // Code.
}

// Incorrect: namespace declaration for the global namespace.
namespace {
    // Code.
}

目前没有将名称空间引入 WordPress Core 的时间表。

强烈建议在插件和主题中使用命名空间。这是为大量代码添加前缀以防止与其他插件、主题和/或 WordPress 核心发生命名冲突的好方法。

请确保您使用唯一且足够长的名称空间前缀以实际防止冲突。一般来说,沿用命名空间前缀Vendor\Project_Name是个好主意。

警告:
和命名空间前缀是为 WordPress 本身保留的wpWordPress

笔记:

define()命名空间对变量、声明的常量或非 PHP 原生构造 没有影响,例如 WordPress 中使用的钩子名称。
那些仍然需要单独添加前缀。

使用导入use语句

使用 importuse语句允许您引用常量、函数、类、接口、名称空间、枚举和存在于当前名称空间之外的特征。

导入use语句应位于文件顶部并跟在(可选)namespace声明之后。他们应该根据导入的类型遵循特定的顺序:

  1. use命名空间、类、接口、特征和枚举的语句
  2. use函数语句
  3. use常量语句

别名可用于防止名称冲突(不同命名空间中的两个类使用相同的类名)。
使用别名时,请确保别名遵循 WordPress 命名约定并且是唯一的。

以下示例展示了use有关间距、分组、前导反斜杠等内容的 import 语句的正确和错误用法。

正确:

namespace Project_Name\Feature;

use Project_Name\Sub_Feature\Class_A;
use Project_Name\Sub_Feature\Class_C as Aliased_Class_C;
use Project_Name\Sub_Feature\{
    Class_D,
    Class_E as Aliased_Class_E,
}

use function Project_Name\Sub_Feature\function_a;
use function Project_Name\Sub_Feature\function_b as aliased_function;

use const Project_Name\Sub_Feature\CONSTANT_A;
use const Project_Name\Sub_Feature\CONSTANT_D as ALIASED_CONSTANT;

// Rest of the code.

错误:

namespace Project_Name\Feature;

use   const   Project_Name\Sub_Feature\CONSTANT_A; // Superfluous whitespace after the "use" and the "const" keywords.
use function Project_Name\Sub_Feature\function_a; // Function import after constant import. 
use \Project_Name\Sub_Feature\Class_C as aliased_class_c; // Leading backslash shouldn't be used, alias doesn't comply with naming conventions.
use Project_Name\Sub_Feature\{Class_D, Class_E   as   Aliased_Class_E} // Extra spaces around the "as" keyword, incorrect whitespace use inside the brace opener and closer.
use Vendor\Package\{ function function_a, function function_b,
     Class_C,
        const CONSTANT_NAME}; // Combining different types of imports in one use statement, incorrect whitespace use within group use statement.

class Foo {
    // Code.
}

use const \Project_Name\Sub_Feature\CONSTANT_D as Aliased_constant; // Import after class definition, leading backslash, naming conventions violation.
use function Project_Name\Sub_Feature\function_b as Aliased_Function; // Import after class definition, naming conventions violation.

// Rest of the code.

警告:
导入use语句对动态类、函数或常量名称没有影响。
use语句从 PHP 7.0 开始可用,组use语句中的尾随逗号从 PHP 7.2 开始可用。

笔记:

请注意,除非您已实现自动加载,否则该use语句不会自动加载正在导入的任何内容。您需要设置自动加载或使用语句加载包含类/函数/常量的文件require/import,以便在使用时加载别名结构。

关于 WordPres Core 使用的注意事项

虽然 importuse语句已经可以在 WordPress Core 中使用,但目前强烈建议不要使用

Importuse语句在与名称空间和类自动加载实现结合使用时最有用。
由于这些目前都没有用于 WordPress Core,并且有关此的讨论正在进行中,因此暂缓use向 WordPress Core 添加导入语句是目前明智的选择。

面向对象编程

每个文件只有一个对象结构(类/接口/特征)

例如,如果我们有一个名为的文件,class-example-class.php它只能包含该文件中的一个类。

// Incorrect: file class-example-class.php.
class Example_Class {}

class Example_Class_Extended {}

第二类应该在它自己的文件中,名为class-example-class-extended.php.

// Correct: file class-example-class.php.
class Example_Class {}
// Correct: file class-example-class-extended.php.
class Example_Class_Extended {}

特征使用语句

特征use语句应该位于类的顶部,并且在第一个语句之前应该有一个空行use,并且在最后一个语句之后至少有一个空行。唯一的例外是当类只包含特征use语句时,在这种情况下可以省略后面的空行。

以下代码示例显示了use关于间距、分组和缩进等特征语句的格式要求。

// Correct.
class Foo {

    use Bar_Trait;
    use Foo_Trait,
        Bazinga_Trait {
        Bar_Trait::method_name insteadof Bar_Trait;
        Bazinga_Trait::method_name as bazinga_method;
    }
    use Loopy_Trait { eat as protected; }

    public $baz = true;

    ...
}

// Incorrect.
class Foo {
    // No blank line before trait use statement, multiple spaces after the use keyword.
    use       Bar_Trait;

    /*
     * Multiple spaces when importing traits, no new line after opening brace.
     * Aliasing should be done on the same line as the method it's replacing.
     */
    use Foo_Trait,   Bazinga_Trait{Bar_Trait::method_name    insteadof     Foo_Trait; Bazinga_Trait::method_name
        as     bazinga_method;
            }; // Wrongly indented brace.
    public $baz = true; // Missing blank line after trait import.

    ...
}

应始终声明可见性

对于所有允许它的构造(自 PHP 7.1 起的属性、方法、类常量),应该显式声明可见性。不允许
使用关键字进行属性声明。var

// Correct.
class Foo {
    public $foo;

    protected function bar() {}
}

// Incorrect.
class Foo {
    var $foo;

    function bar() {}
}

在 WordPress 核心中的使用

在将最低 PHP 版本提高到 PHP 7.1 之前,不能在 WordPress 核心中使用类常量的可见性。

可见性和修饰符顺序

当一个类声明_使用多个修饰符时,顺序应该如下:

  1. 首先是可选的abstractfinal修饰符。
  2. 接下来,可选readonly修饰符。

在面向对象结构中对_常量声明使用多个修饰符时,顺序应如下:

  1. 首先是可选final修饰符。
  2. 接下来,可见性修饰符。

当对一个_属性声明_使用多个修饰符时,顺序应该如下:

  1. 首先是可见性修饰符。
  2. 接下来,可选staticreadonly修饰符(这些关键字是互斥的)。
  3. 最后,可选type声明。

当一个方法声明_使用多个修饰符时,顺序应该如下:

  1. 首先是可选的abstractfinal修饰符。
  2. 然后,可见性修饰符。
  3. 最后,可选static修饰符。
// Correct.
abstract readonly class Foo {
    private const LABEL = 'Book';

    public static $foo;

    private readonly string $bar;

    abstract protected static function bar();
}

// Incorrect.
class Foo {
    protected final const SLUG = 'book';

    static public $foo;

    static protected final function bar() {
        // Code.
    };
}

笔记:

– 自 PHP 7.1 起可以声明 OO 常量的可见性。
– 类型化属性从 PHP 7.4 开始可用。
– 只读属性自 PHP 8.1 起可用。
final自 PHP 8.1 起,面向对象结构中常量的修饰符可用。
– 只读类自 PHP 8.2 起可用。

对象实例化

当实例化一个新的对象实例时,必须始终使用括号,即使不是绝对必要的。
被实例化的类的名称和左括号之间不应有空格。

// Correct.
$foo = new Foo();
$anonymous_class = new class( $parameter ) { ... };
$instance = new static();

// Incorrect.
$foo = new Foo;
$anonymous_class = new class ( $input ) { ... };

控制结构

使用elseif, 不else if

else if与块的冒号语法不兼容if|elseif。因此,请用于elseif条件。

尤达条件

if ( true === $the_force ) {
    $victorious = you_will( $be );
}

在进行涉及变量的逻辑比较时,始终将变量放在右侧,将常量、文字或函数调用放在左侧。如果双方都不是变量,则顺序并不重要。(在计算机科学术语中,在比较中总是尝试将左值放在右边,将右值放在左边。)

在上面的例子中,如果你省略了一个等号(承认这一点,即使是我们中最有经验的人也会发生),你会得到一个解析错误,因为你不能分配给像 . 这样的常量true。如果该语句是相反的( $the_force = true ),则赋值将完全有效,返回1,导致 if 语句计算为true,您可能会追查该错误一段时间。

读起来有点奇怪。习惯了,你会的。

这适用于==!====!==<><=的Yoda 条件>=明显更难阅读,最好避免使用。

运营商

三元运算符

三元运算符很好,但总是让它们测试语句是否为真,而不是假。否则,它只会变得混乱。(一个例外是使用! empty(),因为这里测试 false 通常更直观。)

不得使用短三元运算符。

例如:

// (if statement is true) ? (do this) : (else, do this);
$musictype = ( 'jazz' === $music ) ? 'cool' : 'blah';
// (if field is not empty ) ? (do this) : (else, do this);

差错控制算子@

如PHP 文档中所述:

PHP 支持一种错误控制运算符:at 符号 (@)。在 PHP 中添加到表达式之前时,该表达式可能生成的任何诊断错误都将被抑制。

虽然这个运算符确实存在于 Core 中,但它经常被懒惰地使用,而不是进行适当的错误检查。强烈建议不要使用它,因为甚至 PHP 文档也指出:

警告:在 PHP 8.0.0 之前,@ 运算符可以禁用将终止脚本执行的严重错误。例如,将 @ 添加到调用不存在的函数之前,由于不可用或输入错误,将导致脚本终止,但没有任何指示说明原因。

递增/递减运算符

对于独立语句,前递增/递减应优于后递增/递减。

前自增/自减会先自增/自减再返回,后自增/自减会先返回再自增/自减。
使用“pre”版本的性能稍微好一些,并且可以在代码移动时防止将来出现错误。

// Correct: Pre-decrement.
--$a;

// Incorrect: Post-decrement.
$a--;

数据库

数据库查询

避免直接接触数据库。如果有一个定义的函数可以获取你需要的数据,就使用它。数据库抽象(使用函数而不是查询)有助于保持代码向前兼容,并且在结果缓存在内存中的情况下,它可以快很多倍。

如果您必须接触数据库,请考虑创建一个Trac票证。您可以在那里讨论为未来版本的 WordPress 添加新功能以涵盖您想要的功能的可能性。

格式化 SQL 语句

在格式化 SQL 语句时,您可以将它们分成几行并缩进,如果它足够复杂以保证这样做的话。不过,大多数语句都可以很好地作为一行。始终将语句的 SQL 部分大写,例如UPDATEor WHERE

更新数据库的函数应该期望它们的参数在传递时没有 SQL 斜线转义。转义应尽可能接近查询时间,最好使用$wpdb->prepare()

$wpdb->prepare()是一种处理 SQL 查询的转义、引用和 int 转换的方法。sprintf()它使用格式化样式的子集。例子 :

$var = "dangerous'"; // Raw data that may or may not need to be escaped.
$id = some_foo_number(); // Data we expect to be an integer, but we're not certain.

$wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET post_title = %s WHERE ID = %d", $var, $id ) );

%s用于字符串占位符,%d用于整数占位符。请注意,它们没有被“引用”!$wpdb->prepare()将为我们处理转义和引用。这样做的好处是很容易一眼看出是否有东西被转义,因为它恰好在查询发生时发生。

有关详细信息,请参阅插件手册中的数据验证。

建议

函数参数的不言自明的标志值

true在调用函数时更喜欢字符串值false

// Incorrect.
function eat( $what, $slowly = true ) {
...
}
eat( 'mushrooms' );
eat( 'mushrooms', true ); // What does true mean?
eat( 'dogfood', false ); // What does false mean? The opposite of true?

从 PHP 8.0 开始,PHP 仅支持命名参数。然而,由于 WordPress 目前仍然支持旧的 PHP 版本,我们还不能使用它们。
没有命名参数,标志的值就没有意义,每次我们遇到像上面例子这样的函数调用时,我们都必须搜索函数定义。通过使用描述性字符串值而不是布尔值,可以使代码更具可读性。

// Correct.
function eat( $what, $speed = 'slowly' ) {
...
}
eat( 'mushrooms' );
eat( 'mushrooms', 'slowly' );
eat( 'dogfood', 'quickly' );

当需要更多的词来描述函数参数时,$args数组可能是更好的模式。

function eat( $what, $args ) {
...
}
eat ( 'noodles', array( 'speed' => 'moderate' ) );

使用此模式时要小心,因为如果输入在使用前未经过验证,它可能会导致“未定义的数组索引”通知。仅在有意义的地方(即多个可能的参数)使用此模式,而不仅仅是为了它。

巧妙的代码

一般来说,可读性比巧妙或简洁更重要。

isset( $var ) || $var = some_function();

虽然上面这行代码很巧妙,但如果你不熟悉的话,还是需要花些时间才能理解。所以,就这样写吧:

if ( ! isset( $var ) ) {
    $var = some_function();
}

除非绝对必要,否则不应使用松散的比较,因为它们的行为可能会产生误导。

正确:

if ( 0 === strpos( $text, 'WordPress' ) ) {
    echo esc_html__( 'Yay WordPress!', 'textdomain' );
}

错误:

if ( 0 == strpos( 'WordPress', 'foo' ) ) {
    echo esc_html__( 'Yay WordPress!', 'textdomain' );
}

作业不得放在条件语句中。

正确:

$data = $wpdb->get_var( '...' );
if ( $data ) {
    // Use $data.
}

错误:

if ( $data = $wpdb->get_var( '...' ) ) {
    // Use $data.
}

在一个switch声明中,可以将多个空案例落入一个公共块。如果一个案例包含一个块,则进入下一个块,但是,这必须明确注释。

switch ( $foo ) {
    case 'bar':                // Correct, an empty case can fall through without comment.
    case 'baz':
        echo esc_html( $foo ); // Incorrect, a case with a block must break, return, or have a comment.
    case 'cat':
        echo 'mouse';
        break;                 // Correct, a case with a break does not require a comment.
    case 'dog':
        echo 'horse';
        // no break            // Correct, a case can have a comment to explicitly mention the fall through.
    case 'fish':
        echo 'bird';
        break;
}

goto绝不能使用该语句。

eval()构造_非常危险_且无法保护。此外,该create_function()函数在内部执行eval(),自 PHP 7.2 起已弃用,并已在 PHP 8.0 中删除。这些都不能使用。

闭包(匿名函数)

在适当的情况下,闭包可以用作创建新函数以作为回调传递的替代方法。例如:

$caption = preg_replace_callback(
    '/<[a-zA-Z0-9]+(?: [^<>]+>)*/',
    function ( $matches ) {
        return preg_replace( '/[\r\n\t]+/', ' ', $matches[0] );
    },
    $caption
);

闭包不应作为过滤器或操作回调传递,因为通过remove_action()/删除它们remove_filter()很复杂(此时)(有关解决此问题的建议,请参阅#46635 )。

常用表达

Perl 兼容的正则表达式(PCRE,preg_函数)应该优先使用它们的 POSIX 对应物。切勿使用/e开关,preg_replace_callback而应使用。

对正则表达式使用单引号字符串是最方便的,因为与双引号字符串相反,它们只有两个元序列需要转义:\'\\.

不使用extract()

extract()是一个糟糕的函数,它使代码更难调试和更难理解。我们应该阻止它的 [sic] 使用并删除我们对它的所有使用。

约瑟夫·斯科特 (Joseph Scott) 对它为什么不好有一篇很好的文章。

不允许使用反引号运算符。

反引号运算符的使用与 相同shell_exec(),大多数主机php.ini出于安全原因在文件中禁用此功能。