Заказать проект
Оставьте заявку для получения коммерческого предложения.
Заполните форму и мы вышлем Вам предложение в котором решим,
чем можем вам помочь.
PHP для бабушки: учимся писать читабельный код

PHP для бабушки: учимся писать читабельный код

12 Марта 2018
Александр Гоцалюк
Back End Developer
Александр  Гоцалюк
следующая статья

Эта статья не о каллиграфии и шрифтах. А о том, почему нужно быть аккуратным в своем коде и к чему это приведет.

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

Именно поэтому, мы выделили несколько основных преимуществ качественного кода:

  • Простота в поддержке;
  • Доступно для чтения каждому участнику команды;
  • Удобно при повторном использовании;
  • Легко искать и исправлять ошибки;
  • Использование известных паттернов;
  • Повышает вашу ценность как разработчика;
  • Приветствуется техническим работодателем;
  • Уменьшение рисков помешать бизнесу;

Разберем детальнее эти пункты.
Чтобы облегчить работу в команде себе и другим, для повторного использования кода, вы должны с самого начала беспокоится о качестве написанного. Если спросите себя: “будет-ли кто-то читать мой код?”, то независимо от ответа, его нужно писать качественно. Так как проекты могут поддерживаться годами, бывают случаи когда через полгода разработчики не могут разобраться в написанном ими же коде.

В больших проектах или командах важную роль в качестве проекта отыгрывают комментарии в коде. Главная суть в том, чтобы дать понять другому разработчику с чем и как использовать ту или иную функцию кода. Обычно, комментарии распределяются на многострочные и однострочные. Схема правильного комментария выглядит так: класс -> метод -> код внутри метода. Правильный комментарий упростит жизнь тому в чьи руки попался ваш кода. 


В случае, когда Вы делите свои проекты на “можно писать как угодно” и “нужен высококачественный код”, то всегда остается риск спутать вторую группу с первой. Написание кода в одном стиле значительно ускорит работу.

Если же вы пишете код не на ассемблере или в двоичном коде, то вывод с этого, что ваш PHP создан для того, чтобы быть понятным для людей. То есть, созданный код на “новых” программах верстки всегда должен быть читабельным.

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

Даже при поиске новой работы, качественный код может повысить ваши шансы получить солидную должность. При условии, что ваши будущий работодатель технически образован или тоже программист. Уверяю, ваш код будет тщательно изучен и выброшен в черный список, если выполнен “непрофессионально”. А в этом случае спасет только везение, или указанная графа “начинающий разработчик”. Если вам важна карьера, то следует с самого начала инвестировать время и ресурсы в изучения “красивого” кода.

Рассматриваем примеры:

Казалось бы написание if оператора не должно вызывать проблем, так как он используется практически везде. Часто у начинающих программистов, из за невнимательности или других причин исчезает сравнение (==), а появляется присвоение if ( = ). В результате, код будет выполняется вечно.

if ($_REQUEST['action'] = 'delete') {  
// run the delete code…
}

Соответственно он должен выглядеть так:
if ($_REQUEST['action'] == 'delete') {  
// run the delete code…
}
Но лучше - поменять местами переменные в условии:

if ('delete' == $_REQUEST['action']) {  
// run the delete code…
}

Такой подход защитит от случайного использование `=` вместо `==`. Как и в РНР будет возвращаться ошибка при попытке присвоения значения в строку.


Без повторений

Наверное, самый популярный принцип программирования это “Никогда не повторяйся”. Если приходится писать одинаковый код по несколько раз, нужно обернуть его в функцию или отдельный класс, после чего использовать для избежания повторов. Хороший пример, когда есть два разных класса частично выполняющих одинаковый функционал. Во избежания повторов создаем абстрактный класс который наследуется этими основными классами и реализовывает общий функционал.

Начальный код:

class Foo
{
	private $settings;

    	public function __construct( $settings )
{
$this->setSettings( $settings );
// … some foo code
    	}
	
	protected function setSettings( $settings )
{
        if ( ! is_array( $settings ) ) {
            throw new \Exception( 'Invalid settings' );
        }
        
        $this->settings = $settings;
}

public function work()
{
	// … some foo code
	}
}


class Bar
{
	private $settings;

    	public function __construct( $settings )
{
$this->setSettings( $settings );
// … some bar code
    	}
	
	protected function setSettings( $settings )
{
        if ( ! is_array( $settings ) ) {
            throw new \Exception( 'Invalid settings' );
        }
        
        $this->settings = $settings;
}

public function work()
{
	// … some bar code
	}
}

Преобразуем:

abstract class Base
{
	private $settings;

	protected function setSettings( $settings )
{
        if ( ! is_array( $settings ) ) {
            throw new \Exception( 'Invalid settings' );
        }
        
        $this->settings = $settings;
}
}

class Foo extends Base
{
	public function __construct( $settings )
{
$this->setSettings( $settings );
// … some foo code
    	}


public function work()
{
		// … some foo code
	}
}


class Bar extends Base
{
	public function __construct( $settings )
{
$this->setSettings( $settings );
// … some bar code
    	}
	
public function work()
{
	// … some bar code
	}
}

Распределение комплексных функций

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

function getSettings() 
{
    if ($this->hasParameter('settings')) {
        $settings = $this->getParameter('settings');
    } else if ($this->hasParameter('setting')) {
        $settings = [ $this->getParameter('setting') ];
    }

    if (isset($settings)) {
        $root = $this->getParameter('root');
        if (!$root) {
            if (isset($_SERVER['PWD'])) {
                $root = $_SERVER['PWD'];
            } else if (isset($_SERVER['DOCUMENT_ROOT'])) {
                $root = $_SERVER['DOCUMENT_ROOT'];
            }
        }

        $settings['root'] = $root;
    }

    return $settings;
}

Намного проще и понятнее для чтения метод ниже:

function getBaseSettings()
{
		if ($this->hasParameter('settings')) {
        		return $this->getParameter('settings');
    	} else if ($this->hasParameter('setting')) {
       		return [ $this->getParameter('setting') ];
   	}
	return [];
	}

	function getRootFolder()
{
$root = $this->getParameter('root');
if (!$root) {
            	$root = $_SERVER['PWD'];
            }

	if (!$root) {
                $root = $_SERVER['DOCUMENT_ROOT'];
            }

	return $root;
}

function getSettings() 
{
	$settings = $this->getBaseSettings();
	if ($settings) {
		$settings['root'] = $this->getRootFolder();
	}

	return $settings;
}

При разбитии комплексных блоков лучше использовать упрощения условных выражений. Часто может встречаться такое условие:

if (isset($data['action']) && is_string($data['action']) && in_array($data['action'], ['add', 'get', 'delete'])) {
	echo 'very nice';
}

Но если вынести условие в отдельную функцию и дать ей соответствующее название, это даст нам несколько преимуществ. 

function isValid($data)
	{
		return isset($data['action']) && is_string($data['action']) && in_array($data['action'], ['add', 'get', 'delete']);
	}

	if (isValid($data)) {
		echo 'very nice';
}

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

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

function getSetting ($key, $default = '')
	{
		$settings = $this->getSettings();
		
		if ($key) {
			if (is_array($key)) {
				return $this->filterSetting($key);
			} else {
				if ( 'prefix' == $key && !isset($settings['prefix']) {
					return $this->getDefaultPrefix();
				} else {
					if (is_string($key) && isset($settings[$key]) {
						return $settings[$key];	
					}
					return $default;
				}
			}
		} else {
			return $this->getErrorSetting($key);
		}
	}

При последующем усложнении эта функция может перерасти в полный “ад” из условий. Для избежания этого, вложенные условия заменяют граничными операторами:

function getSetting ($key, $default = '')
	{
		if (boolval($key) === false)
			return $this->getErrorSetting($key);

		if (is_array($key))
return $this->filterSetting($key);
		$settings = $this->getSettings();
		
if ( 'prefix' == $key && !isset($settings['prefix'])
			return $this->getDefaultPrefix();

if (is_string($key) && isset($settings[$key])
return $settings[$key];	
					
		return $default;
	}


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

В статье прописаны рекомендации по решению самых распространенных ошибок в коде. С некоторыми примерами вы можете не соглашаться, но лучше всегда быть готовым к последствиям, которые скрывает “плохой” код.

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

Записаться На Консультацию
Записаться На Консультацию
Мы свяжемся
с вами
в течении
10 минут
laptop
Мы свяжемся с вами в течении 10 минут