Использование null значений в методах PHP

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

В интернете часто можно встретить вопрос, нужно ли передавать NULL в параметрах методов, а также возвращать NULL из методов. Если нет, то почему и как писать код в таких случаях? Об этом и пойдёт речь в статье.

В чём вообще проблема использования null значений? Дело в том, что NULL можно трактовать по разному — это когда значение неизвестно, его используют в качестве значений по умолчанию для параметров методов, возвращают когда не смогли получить успешный результат или когда что-то произошло не так. Есть куча способов и причин использовать NULL. Однако это не всегда приемлемо.

Передача null в параметры

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

Например, предположим, что у вас есть метод, который принимает параметр $name:

<?php

public function greet($name) {
    echo "Hello, $name!";
}

Если вы хотите обрабатывать случаи, когда он не указан, вы можете установить для параметра $name значение по умолчанию NULL:

<?php

public function greet($name = null) {
    if ($name === null) {
        echo "Hello, World!";
    } else {
        echo "Hello, $name!";
    }
}

В этом случае, если вы вызываете greet() метод без передачи каких-либо аргументов, он примет для параметра $name значение NULL по умолчанию.

Причина отказа от NULL заключается в том, что не нужно постоянно его проверять, если вы ожидаете в значении какое-то другое содержимое. Вместо этого вы можете вернуть, пустой массив, если ожидаемый результат — это массив. Если это целое число, возможно, будет достаточно 0, если это строка, то пустая строка и так далее. 

Но есть и другие способы передачи и проверки аргументов метода. К примеру, можно передавать аргументы в виде массива:

<?php

function getParams(array $params) {
    return [
        'columns' => $buttonParameters['col'],
        'rows' =>  $params['count']
        'count' => $params['count']
    ];
}

Другой вариант, не указывать аргументы функции явно, а воспользоваться динамическими аргументами. В этом поможет функция func_get_args(). И в теле уже самой функции просто валидировать получаемые функцией аргументы:

<?php

function getParamsFunction()
{
    var_dump(func_get_args());
}
getParamsFunction(1, 2, 3, 7, 10, 12);

Дополнительно можно использовать функции func_num_args() и func_get_arg().

Однако эти два способа сильно ухудшают понимание кода и требует множество дополнительных проверок каждого параметра. Поэтому эти способы создают ещё больше хлопот, чем использование NULL по умолчанию. Тем не менее эти способы частенько можно встретить.

В PHP 8 появились именованные аргументы. Теперь передать параметры можно следующим образом:

<?php

function params($a = 1, $b = 2) {
    print "a: $a, b: $b";
}

params(b: 5); // Выведет "a: 1, b: 5"

В этом случае аргументы функции передаются по имени параметра, а не по его позиции. Аргумент не зависит от порядка и указанного значения по умолчанию. Именованный аргумент передаётся с помощью добавления двоеточия перед значением имени параметра. Для имени параметра можно использовать зарезервированные слова. Однако имя не может быть создано динамически и должно быть идентификатором.

Возврат null из метода

Обычно из функции возвращают false, если что-то пошло не так. Аналогичное делают и стандартные функции PHP. Для этих же целей возвращают NULL, пустую строку, пустой массив или вообще ничего. В общем, у каждого свой поход и причины возвращать то или иное значение. Многие даже как-то не сильно об этом задумываются. Однако в некоторых случаях, возврат NULL как и возврат других значений, которые изначально не подразумевались для возврата, могут приводить к ошибкам и непонятным замешательствам. Здесь конечно же серьёзную роль играет сам PHP, поскольку типы данных в нём слабо типизированы и мы можем вертеть данными как угодно.

К примеру, возьмем такой метод:

<?php

function getClients()
{
  $query = 'SELECT * FROM clients';
  $result = $this—>mysqli—>query($query);

  if ($result) {
    return false;
  }

  $data = [];

  while ($row = $result->fetch_assoc())
  {
    $data[] = $row;
  }


  return $data;
}

В нём мы собираемся получить список клиентов из базы данных. Если клиенты успешно получены, мы возвращаем массив, а если что-то пошло не так, то метод возвращает false. Затем мы используем данный метод, чтобы далее проводить операции с клиентами:

<?php

$result = $db—>getClients();

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

<?php

$result = $db—>getClients();

if (!$result) {
// что-то произошло не так
}
// работаем с массивом клиентов

В этом примере идёт неявная проверка данных, поэтому даже если функция getClients() возвращает пустой массив, то условие сработает. Поэтому лучше проверять на конкретный тип данных:

<?php

$result = $db—>getClients();

if ($result === false) {
// что-то произошло не так
}

if (count($result) === 0) {
 // пустой результат
}

// а если не false и array не пустой, то работаем с массивом клиентов

Если мы используем вместо false другое значение, пустую строку или NULL, то ситуация может возникнуть практически такая же. Как в таком случае лучше изменить код и что использовать?

Вместо возврата false, пустой строки или NULL можно использовать исключения. Это позволит сразу же определить, что именно и на каком моменте произошло.

<?php

function getClients()
{
  $query = 'SELECT * FROM clients';
  $result = $this—>mysqli—>query($query);

  if ($result) {
    throw new ErrorException('Произошла такая-то ошибка');
  }

  $data = [];

  while ($row = $result->fetch_assoc())
  {
    $data[] = $row;
  }


  return $data;
}

Затем при использовании метода обработать это исключение:

<?php

try {
  $result = $db—>getClients();
  // все норм, двигаемся дальше
} catch (ErrorException $e) {
  // схватили ошибку!
}

Здесь уже не нужно дополнительно проверять на всякие false или NULL и можно быть точно уверенным, почему метод не отдал правильные данные. Важно лишь правильно перехватывать и обрабатывать такие исключения.

<?php

public getFileSize(File $file) {
  if (!$file—>exists()) {
    return null;
  }
  return $file—>getLength();
}

В этом простом примере метод возвращает размер файла. Если файла не существует, то возвращается NULL, 0 или пустая строка — неважно. Вот здесь и начинается проблема, что файла не существует, он был перемещён или удалён, но вместо того чтобы узнать об этом, подобная проверка маскирует проблему. В этом случае можно использовать исключение:

<?php

public getFileSize(File $file) {
  if (!$file—>exists()) {
     throw new Exception(
      "Нельзя получить размер файла. Файл не найден!"
    );
  }
  return $file—>getLength();
}

Начиная с PHP7 для функций можно установить тип возвращаемого значения. Например:

<?php

function getValue(): int {
  return 777;
}

Результат:

int(777)

Если указать цифру строкой:

<?php

function getValue(): int {
  return '777';
}

То она автоматически будет преобразована в int.

Результат:

int(777)

Чтобы включить строгую типизацию, нужно установить:

declare(strict_types=1);

Тогда если попытаться задействовать в этой функции строку, будет выдана ошибка:

Uncaught TypeError: Return value of getValue() must be of the type integer, string returned

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

<?php

function getValue() : ?int {
  return null;
}

Кроме этого, если в методе вообще не использовать return или просто указать его без всякого значения, метод вернёт NULL. Например:

<?php

function getValue1(){
  return;
}

function getValue2() {
}

Поскольку return;и return null; эквивалентны в PHP, то если возвращаемое значение не указано, PHP выполнит работу NULL за вас. То же самое касается и свойств объектов. По умолчанию они имеют значение NULL до тех пор, пока не будут заданы. Поскольку это поведение по умолчанию, лучше помнить об этом и проверять свойства, которые имеет ваш класс, прежде чем совершать вызовы или что-то ещё.

В большинстве случаев рекомендуется возвращать Null-object который предоставляет поведение по умолчанию в зависимости от того как реагирует ваш код на ситуацию когда ничего не найдено.

Так что же в итоге возвращать?

Все индивидуально, зависит от проекта. Главное следовать установленной спецификации в рамках проекта, чтобы соблюдался единый стиль. Проверка нулевых значений — обычная практика, иначе вы рискуете повсюду получить исключения. Лучше корректно обработать ошибку, чем генерировать исключения, когда в этом нет необходимости. NULL это не обязательно плохо, как и в случае со многими другими решениями, это зависит от ситуации.

Использование NULL может быть допустимо, когда это целесообразно и не противоречит остальным частям проекта. В большинстве случаев null следует либо заменить выдачей исключения, либо предоставлением нулевого объекта.

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

Источник: https://habr.com/ru/articles/768886/


Интересные статьи

Интересные статьи

Анализ текстовых данных становится все более важным в наше время, когда огромные объемы информации генерируются и обмениваются каждую секунду. От социальных медиа до новостных порталов, от клиентских ...
В предыдущей статье мы закончили на том, что мы написали лексический и синтаксический анализаторы для нашего учебного языка. В данной статье мы продолжим начатое и рассмотрим следующую стадию анализа ...
В данной статье мы бы хотели описать использованный нами ООП подход к отправке писем через данный сервис рассылок на php. Суть которого заключается в создании объекта инкапсулирующего данные необходим...
Перцептивное хеширование - это использование алгоритма, который создает фрагмент или отпечаток пальца различных форм мультимедиа. (Источник)Есть хорошая статья на Habr’е с которой можно ознакомиться ...
Привет! В этой статье я расскажу о ещё двух вариантах VPN, используемых нами для включения клиентов с помощью Мультисим Резервирования, это L2TP и L2-VPN. Первы...