WordPress как на ладони
Мощный и не дорогой хостинг от Fornex.com Хостинг, VPS/VDS и отдельные сервера только на SSD дисках. 7 дней бесплатного тестирования.

PHP код в WordPress — лучшие практики

Чтобы код WordPress везде был оформлен в одном стиле и удобно читался в ядре, плагинах и темах, рекомендуется соблюдать стандарты написания кода, которые приняты разработчиками WordPress. Эти стандарты очень похожи на стандарт PEAR, однако есть и кардинальные отличия. Рекомендую ознакомится с ними и при создании плагинов или тем, по возможности, их соблюдать.

Кроме стандартов к написанию самого кода PHP, также есть стандарты документирования кода - это комментарии к функциям и хукам: PHP Documentation Standards (англ.)

Одинарные и двойные кавычки

Если в строке нет переменных, используйте одинарные кавычки, в других случаях двойные. Не нужно экранировать кавычки в строке и если они они есть, то рекомендуется их чередовать:

echo '<a href="/static/link" title="Yeah yeah!">Link name</a>';
echo "<a href='$link' title='$linktitle'>$linkname</a>";

Вторая строка в этом примере не очищает выводимые переменные, а это необходимо делать в целях безопасности. Поэтому для такой записи, переменные должны быть очищены заранее. В целом, такую запись можно считать неприемлемой! См. раздел учебника безопасный вывод.

меню

Отступы

Отступ должен всегда показывать логическую структуру кода. Используйте табуляцию (клавиша Tab), а не пробелы - это дает больше гибкости. Пробелы стоит использовать, когда нужно выравнять что-либо внутри строки.

Правило: табуляция должна быть использована в начале строки для отступа, в то время как пробелы могут быть использованы в середине строки для выравнивания.

if ( условие ) {
	$foo     = 'somevalue';
	$foo2    = 'somevalue2';
	$foo_bar = 'somevalue3';
	$foo5    = 'somevalue4';
}

А так код выглядит, если показать невидимые символы табуляции и пробела:

if ( условие ) {
———$foo.....= 'somevalue';
———$foo2....= 'somevalue2';
———$foo_bar.= 'somevalue3';
———$foo5....= 'somevalue4';
}

Для ассоциативных массивов, значения должны начинаться с новой строки. Рекомендуется ставить «последнюю» запятую при перечислении элементов массива - так удобнее добавлять новые элементы...

$my_array = array(
———'foo'...=> 'somevalue',
———'foo2'..=> 'somevalue2',
———'foo3'..=> 'somevalue3',
———'foo34'.=> 'somevalue3',
);
меню

Стиль фигурных скобок

Фигурные скобки должны использоваться для всех блоков в стиле, как показано ниже:

if ( условие ) {
	action1();
	action2();
} elseif ( условие2 && условие3 ) {
	action3();
	action4();
} else {
	defaultaction();
}

Если идет длинный блок, его по возможности нужно разбить на два или более коротких блоков или функций. Если такой длинный блок необходим, добавьте краткий комментарий в конце, чтобы можно было понять, что именно закрывает фигурная скобка. Такой подход логично применять для блока с 35 и более строк.

Следует комментировать любой код, который интуитивно не понятен.

Используйте фигурные скобки всегда, даже если они не требуются.

if ( условие ) {
	action0();
}

if ( условие ) {
	action1();
} elseif ( условие2 ) {
	action2a();
	action2b();
}

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

Обратите внимание, что требование использовать фигурные скобки всегда означает, что одиночные конструкции в стиле одной строки - запрещены.

Можно использовать альтернативный синтаксис для управляющих структур: if / endif, while / endwhile - особенно это актуально для шаблонов, где PHP код встраивается в HTML:

<?php if ( have_posts() ) : ?>
	<div class="hfeed">
		<?php while ( have_posts() ) : the_post(); ?>
			<article id="post-<?php the_ID() ?>" class="<?php post_class() ?>">
				<!-- ... -->
			</article>
		<?php endwhile; ?>
	</div>
<?php endif; ?>
меню

Используйте elseif, а не else if

elseif и else if будут одинаково работать только при использовании фигурных скобок. Если используются синтаксис с двоеточием для определения условий нужно использовать elseif, иначе мы получим фатальную ошибку PHP.

// Некорректный способ:
if( $a > $b ) :
	echo "$a больше, чем $b";
else if( $a == $b ) :
	echo "Строка выше вызывает фатальную ошибку.";
endif;

// Корректный способ:
if( $a > $b ) :
	echo "$a больше, чем $b";
elseif( $a == $b ) :
	echo "$a равно $b";
else:
	echo "$a не больше и не равно $b";
endif;

Многострочный вызов функции

При разбиении параметров функции на несколько строк, каждый параметр должен находиться на отдельной строке. Так комментарии к параметрам смогут иметь собственную строку.

Каждый параметр должен занимать не более одной строки. Многострочные параметры нужно переносить в переменную, а в вызов функции передавать уже эту переменную.

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

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

Регулярные выражения

Используйте строки в одинарных кавычках для регулярных выражений, так как, в отличие от двойных кавычек, у них есть только два символа, который нужно экранировать: \' и \\.

Открытие и закрытие тегов PHP

При добавлении многострочных PHP кодов в HTML блок PHP теги открытия и закрытия должны быть расположены на отдельной строке.

// Правильно (многострочный):
function foo() {
	?>
		<div>
		<?php
		echo bar(
			$baz,
			$bat
		);
		?>
		</div>
	<?php
}

// Правильно (однострочный):
<input name="<?php echo esc_attr( $name ); ?>" />

// Неправильно
if ( $a === $b ) { ?>
<some html>
<?php }

Не используйте короткие PHP теги

Никогда не используйте короткие PHP теги для публичных проектов (например плагинов), потому что на некоторых серверах их обработка может быть отключена и ваш код не будет работать...

Правильно:

<?php ... ?>
<?php echo $var; ?>

Неправильно:

<? ... ?>
<?= $var ?>

Удаляйте пробелы на конце строк

Удаляйте замыкающие пробелы в конце каждой строки.

Опускайте закрывающий тег PHP в конце файла. Если закрывающий PHP тег все же используется, убедитесь, что после него нет пробелов или переносов строк.

Так писать не следует:

<?php
$foo = 'строка';пробел
?>

Конец файла

Нужно так:

<?php
$foo = 'строка';

Конец файла

Использование пробела

Всегда ставьте пробелы после запятых, и на обеих сторонах логических операторов (! && ||), операторов сравнения (==), конкатенации (.) и операторов присваивания (.=).

x == 23
foo && bar
! foo
array( 1, 2, 3 )
$baz . '-5'
$term .= 'X'

Ставьте пробелы на обеих сторонах открывающих и закрывающих круглых скобок для блоков if, elseif, foreach, switch.

if ( $foo ) { ...

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

При определении функции, используйте пробелы так:

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

При вызове функции, так:

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

При выполнении логических сравнений, так:

if ( ! $foo ) { ...

При приведении типа, так:

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

$foo = (boolean) $bar;

При обращении к элементам массива, добавляйте пробел вокруг индекса, только если это переменная:

$x = $foo['bar'];   // правильно
$x = $foo[ 'bar' ]; // неправильно

$x = $foo[0];       // правильно
$x = $foo[ 0 ];     // неправильно

$x = $foo[ $bar ];  // правильно
$x = $foo[$bar];    // неправильно

В блоке switch перед двоеточием оператора case не должно быть пробела.

switch ( $foo ) {
	case 'bar': // correct
	case 'ba' : // incorrect
}

Аналогично, перед двоеточием в объявлениях возвращаемого типа не должно быть пробела.

function sum( $a, $b ): float {
	return $a + $b;
}

Скобки внутри скобок должны иметь пробелы:

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

my_function( ( $x - 1 ) * 5, $y );
меню

Форматирование SQL конструкций

При форматировании SQL запроса, если запрос сложный, его можно разбить на несколько строк и добавить где нужно отступы. Хотя большинство конструкций пишутся в одну строку. Всегда пишите прописными такие части SQL конструкций, как: UPDATE, WHERE, FROM, JOIN.

Очистка, экранирование запроса должна быть сделана как можно позднее. Для защиты запроса рекомендуется использовать $wpdb->prepare(), а не esc_sql().

$var = "dangerous'";      // необработанные данные, которые могут быть экранированы или не экранированы
$id  = some_foo_number(); // данные ожидаются как число, но мы не уверены

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

%s используется для строк и %d для целых чисел. Обратите внимание, что они не 'в кавычках'! $wpdb->prepare() сам экранирует строки и добавляет кавычки, если надо. Преимущество prepare() в том, что не нужно помнить о ручном использовании esc_sql(), а также, что строка запроса с плейсхолдерами более наглядна, чем если бы там использовались переменные обернутые в esc_sql().

Смотрите описание метода $wpdb->prepare().

меню

Запросы базы данных

Старайтесь не писать прямых запросов к базе данных. Если есть подходящая функция, а их в WP много, которая может получить необходимые данные - используйте ее.

Использование функций вместо запросов, помогает сохранить будущую совместимость кода. Кроме того многие функции работают с кэшем, а это может значительно ускорить работу кода.

Имена классов, функций, файлов, констант, переменных

Имена функций, переменных, хуков

Используйте строчные буквы a-z в переменных, хуках и названиях функций и никогда CamelCase. Разделяйте отдельные слова нижним подчеркиванием _. Не сокращайте имена переменных без необходимости; пусть код будет однозначным и само-документированным.

function some_name( $some_variable ) { [...] }
Имена классов

Нужно использовать слова с Заглавных_Букв, разделенные подчеркиванием. Любые сокращения (акронимы, аббревиатуры) должны быть ПРОПИСНЫМИ.

class Walker_Category extends Walker { [...] }
class WP_HTTP { [...] }

Константы должны быть словами в ВЕРХНЕМ_РЕГИСТРЕ, разделенные нижним подчеркиванием:

define( 'DOING_AJAX', true );
Названия файлов

Должны быть понятные и должны также содержать только строчные буквы, а слова должны разделяться дефисом -.

my-plugin-name.php
Названия файлов классов

Должны быть основаны на имени класса с приставкой class- , подчеркивания в имени класса заменены дефисом, например WP_Error становится:

class-wp-error.php

Этот стандарт именования файлов справедлив для всех существующих и новых файлов с классами. Однако существуют файлы исключения: class.wp-dependencies.php, class.wp-scripts.php, class.wp-styles.php. Эти файлы имеют префикс class., точка после слова class вместо дефиса.

В ядре, в папке wp-includes есть подключаемые файлы, в которых находятся функции, которые обычно используются в темах (в шаблоне). Файлы с такими функциями - тегами шаблона заканчиваются на -template.

меню

Понятные значения переменных в параметрах функций

Булевам, предпочтительны строковые значения. Т.е. вместо true/false при вызове функций лучше использовать какую-то объясняющую значение параметра строку.

Плохой код:

function eat( $what, $slowly = true ) {
	...
}
eat( 'mushrooms' );
eat( 'mushrooms', true ); // что означает true?
eat( 'dogfood', false );  // что означает false, противоположность true?

Так как PHP не поддерживает именованные аргументы, значения флагов бессмысленны и каждый раз, когда мы сталкиваемся с вызовом функции, как в примерах выше, нам нужно смотреть документацию по функции. Код может быть более читаемым с помощью описательных строковых значений, вместо булевых.

Хороший код:

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

Когда нужно больше параметров функции, используйте массив $args. Он даже лучше!

Очень хороший код:

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

Интерполяция для имен динамических хуков

Для удобства чтения и обнаружения, хуки с переменными в названии должны быть интерполирован (заключен в фигурные скобки { и }), и не должны конкатенироваться:

Скобки нужны, чтобы PHP мог корректно анализировать типы данных переменных в интерполированной строке.

// правильно
do_action( "{$new_status}_{$post->post_type}", $post->ID, $post );

// неправильно
do_action( $new_status .'_'. $post->post_type, $post->ID, $post );

Там, где это возможно, динамические значения в именах тегов также должны быть максимально краткими и точными. $user_id гораздо понятнее чем, скажем, $this->id.

меню

Тернарный оператор

Тернарные операторы хороши, но в них рекомендуется всегда проверять правдивое утверждение, а не ложное. Иначе он просто вводит в заблуждение из-за двойного отрицания. Исключение - это использование ! empty(), потому что по-другому иногда просто сложно записать.

Как нужно проверять:

// (если условие выполняется = true) ? (то делаем это) : (иначе это);
$music_type = ( 'jazz' == $music ) ? 'cool' : 'blah';
// (если значение не пустое - ! empty ) ? (то делаем это) : (иначе это);

Как не следует писать:

// (если условие не выполняется != true) ? (то делаем это) : (иначе это);
$music_type = ( 'jazz' != $music ) ? 'blah' : 'cool';
меню

Условия Магистра Йоды

При выполнении логических сравнений, всегда ставьте константы или литералы - слева, а переменную - справа.

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

Если пропустить второй знак = в приведенном примере (признаться, это происходит даже с самыми опытными из нас), то мы получим ошибку PHP и сразу её увидим, потому что код не будет работать. А вот если бы конструкция была обратной - $the_force = true, то условие всегда будет выполняться и никакой ошибки мы не увидим, и можем пропустить такой серьезный баг, который к тому же иногда сложно отловить!

К такому «перевернутому» написанию просто нужно привыкнуть.

Это относится и к == , != , === и !==. «Условия Йоды» для <, >, <= или >= значительно труднее читать и тут их лучше не использовать.

меню

Умный код

Если говорить коротко, то читаемость кода должна быть на первом плане, она важнее краткости или каких-то не очевидных, но удобных сокращений.

isset( $var ) || $var = some_function();
// или 
! isset( $var ) && $var = some_function();

Да - это крутая запись, видно что сделал её опытный программист. Но любому другому разработчику, а зачастую даже и автору, для того чтобы разобраться в такой записи нужно немного вникать и потратить лишние секунды или минуты. Это не очевидная и не понятная запись и её нужно избегать, и лучше её записать длиннее, но понятнее:

if ( ! isset( $var ) ) {
	$var = some_function();
}
меню

Оператор подавления ошибок @

Из PHP документации:

PHP поддерживает один оператор управления ошибками: знак @. В случае, если он предшествует какому-либо выражению в PHP-коде, любые сообщения об ошибках, генерируемые этим выражением, будут проигнорированы.

В то время как этот оператор существует в ядре, он часто используется потому что лень нормально обработать переменную. Его использование настоятельно не рекомендуется, так как даже PHP документация заявляет:

Внимание: На сегодняшний день оператор "@" подавляет вывод сообщений даже о критических ошибках, прерывающих работу скрипта. Помимо всего прочего, это означает, что если вы использовали "@" для подавления ошибок, возникающих при работе какой-либо функции, в случае если она недоступна или написана неправильно, дальнейшая работа скрипта будет остановлена без каких-либо уведомлений.

меню

Не используйте функцию extract()

По мотивам тикета #22400. extract() это ужасная функция, которая сильно усложняет отладку кода, также сильно усложняет читаемость и понимание кода. Поэтому никогда не используйте extract(), кроме случаев когда без неё не обойтись, т.е. никогда!

Почему extract() такая ужасная, хорошо объясняет Джозеф Скотт (англ.): I Don’t Like PHP’s extract() Function.

-

Статья подготовлена по материалам документации: PHP Coding Standards

Eugene Kopich 100eugenekopich.com
Revamped Design/Marketing
Редакторы: Kama 7099
1 коммент
  • Максим

    Спасибо за статью, узнал полезное про именование файлов и "Условия Магистра Йоды".

    1
Здравствуйте, !     Войти . Зарегистрироваться