Posts Tagged ‘php’

Меньше кода ?== больше ям

Posted in Статьи on ноября 15, 2007 by korchasa – Be the first to comment

Вроде бы все всё знают, но почему не все всё используют? Меньше кода, хорошего и разного? Или читаемость все таки теряется?

1. Присвоение в сравнениях

Больше:

$id = $request->getId();
if(!$id) {
 return false;
}

Меньше:

if(!$id = $request->getId()) {
 return false;
}

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

2. Тернарный оператор, вместо if

Больше:

if($id) {
 return $id;
} else {
 return false;
}

Меньше:

return ($id) ? $id : false;

Читаемость нисколько не снижается. ИМХО их и объединять можно:

$a = ($a) ? a : ($b) ? $b : 'default';

3. “Вытаскивание” элементов массива в текущий контекст

Больше:

function resolveArray($params) {
 if(array_key_exists('foo', $params)) {
   return $params['bar'];
 }
}

Меньше:

function resolveArray2($params) {
 extract($params);
 if(isset($foo)) {
   return $bar;
 }
}

или

function resolveArray3($params) {
 list($foo, $bar) = $params;
 if(isset($foo)) {
   return $bar;
 }
}

Использование extract – несколько порочная практика, ибо непонятно откуда переменные берутся. Использование list’а в этом плане лучше, но он завязан на порядок следования элементов…гад.

Поэтому в больших методах лучше все таки вытаскивать “ручками”:

function resolveSomeArrayInformation3($params) {
 $foo = array_key_exists('foo', $params) ? $params['foo'] : false;
 $bar = array_key_exists('bar', $params) ? $params['bar'] : false;
 if(isset($foo)) {
   return $bar;
 }
}

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

4. Инициализация в объявлении цикла

Больше:

$count = count($array);
for($i = 0; $i < $count; $i++) {}

Меньше:

for($i = 0, $count = count($array); $i < $count; $i++) {}

Вполне нормально для меня, для остальных, говорят, не очень.

5. Операции в объявлении цикла

Больше:

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

Меньше:

for($i = 0; $i < 10; $str .= $i++);

Тоже самое, что и в предыдущем.

6. Простое позиционирование в строке

Больше:

$current_letter = substr($str, $i, 1);

Меньше:

$current_letter = $str{$i};

Читаемость лучше, однозначно стоит применять.

И так далее...

Перегрузка методов и свойств в PHP

Posted in Тесты on мая 17, 2007 by korchasa – Be the first to comment

Задача: Проверить насколько перегруженные методы и свойства медленнее явных.

Публичные методы

Набросаем небольшой класс:

class Classic {
  public $fooProp;
  public $barProp;

  public function getFooProp() {
      return $this->fooProp;
  }

  public function setFooProp($foo) {
      $this->fooProp = $foo;
  }

  public function getBarProp() {
      return $this->barProp;
  }

  public function setBarProp($bar) {
      $this->barProp = $bar;
  }
}

Проведем тест на скорость выполнения публичных методов. Исходя из

$iterations = 10000;
echo '

Доступ через прописанные сеттеры/геттеры  - ';
$time_start = microtime(1);
for ($i=0; $i < $iterations; $i++) {
  $obj = new Classic();
  $obj->setFooProp($i);
  $tmp = $obj->getBarProp();
  $tmp = $obj->getFooProp();
  $tmp = $obj->getBarProp();
  $tmp = $obj->getFooProp();
  $tmp = $obj->getBarProp();
  $tmp = $obj->getFooProp();
  $tmp = $obj->getBarProp();
  $tmp = $obj->getFooProp();
  $tmp = $obj->getBarProp();
}
$times = round($iterations / (microtime(1) - $time_start));
echo $times . ' в секунду

';

Результаты тестов на 10000 итераций:

Доступ через прописанные сеттеры/геттеры - 136552 в секунду

Перегрузка обращений к свойствам объекта (__set, __get)

Класс Overloaded реализует функционал класса Classic, с помощью перегрузки методов(__call) и доступа к свойствам(__set, __get):

Overloaded {
  protected $fields = array(
  'fooProp' => false,
  'barProp' => false
  );

  protected function _generateNoPropertyException($prop) {
      throw new Exception('Undefined property ' . $prop);
  }

  public function __get($name) {
      if(isset($this->fields[$name])) {
          return $this->fields[$name];
      } else {
          $this->_generateNoPropertyException($name);
      }
  }

  public function __set($name,$value) {
      if (isset($this->fields[$name])) {
          $this->fields[$name] = $value;
      } else {
          $this->_generateNoPropertyException($name);
      }
  }

  public function getBarProp() {
      return $this->fields['barProp'];
  }

  protected function __call($mthd, $args = array()) {
      $type = substr($mthd, 0, 3);
      if('get' == $type) {
          return $this->__set(strtolower(substr($mthd, 3, 1)).substr($mthd, 4),$args);
      } elseif('set' == $type) {
          return $this->__get(strtolower(substr($mthd, 3, 1)).substr($mthd, 4));
      }
      throw new Exception("No such method '$mthd' in " . get_class($this));
  }
}

Протестируем:

echo '

Доступ через перегруженные сеттеры/геттеры  - ';
$time_start = microtime(1);
for ($i=0; $i < $iterations; $i++) {
  $obj = new Overloaded();
  $obj->fooProp = $i;
  $tmp = $obj->barProp;
  $tmp = $obj->fooProp;
  $tmp = $obj->barProp;
  $tmp = $obj->fooProp;
  $tmp = $obj->barProp;
  $tmp = $obj->fooProp;
  $tmp = $obj->barProp;
  $tmp = $obj->fooProp;
  $tmp = $obj->barProp;
}
$times = round($iterations / (microtime(1) - $time_start));
echo $times . ' в секунду

';

Получаем результат:

Доступ через перегруженные сеттеры/геттеры - 56004 в секунду

Перегрузка методов (__call)

Тестировать будем на нашем классе Overloaded:
echo

Доступ через эмулированные сеттеры/геттеры – ‘

;
$time_start = microtime(1);
for (
$i=0; $i < $iterations; $i++) {
$obj = new Overloaded();
$obj->setFooProp($i);
$tmp = $obj->getBarProp();
$tmp = $obj->getFooProp();
$tmp = $obj->getBarProp();
$tmp = $obj->getFooProp();
$tmp = $obj->getBarProp();
$tmp = $obj->getFooProp();
$tmp = $obj->getBarProp();
$tmp = $obj->getFooProp();
$tmp = $obj->getBarProp();
}
$times = round($iterations / (microtime(1) – $time_start));
echo
$times . ‘ в секунду’;

highlight_file(__FILE__);
Результат:

Доступ через эмулированные сеттеры/геттеры - 27468 в секунду

Выводы

Вот результаты всех трех тестов:

Доступ через прописанные сеттеры/геттеры - 136552 в секунду
Доступ через перегруженные сеттеры/геттеры - 56004 в секунду
Доступ через эмулированные сеттеры/геттеры - 27468 в секунду

На диаграмме это выглядит следующим образом:

Сравнительно большая разница. Но если учесть, что сервер на котором проводилось тестирование достаточно сильно загружен, и тем не менее способен ежесекундно обрабатывать примерно 27,5 тысяч объектов, то отказ от использования overload это экономия на спичках в чистом виде.

Исходники полного теста: setget.php (3,2 Кб)