Xpoint
   [напомнить пароль]

Готовые решения

Оглавление

Кэширование результата функции в static-переменной

Это очень простой паттерн, позволяющий сэкономить время на вызовах функций, результат действия которых зависит только от входных параметров. Идея в том, что результат действия функции кэшируется в её внутренней static-переменной (значение которой не теряется при выходе из функции).

<?php
function someFunction($foo) {
  static $cache = array();
  if(isset($cache[$foo])) return $cache[$foo];
  /*
    Очень долгое и трудоёмкое вычисление 
    значения величины $result из величины $foo
  */
  $cache[$foo] = $result;
  return $result;
}
?>

Реализация паттерна "Одиночка" (Singleton) для PHP 4

Этот паттерн удобно использовать, если требуется иметь в системе только один экземпляр объекта (это может быть, к примеру, интерфейс базы данных). Однако в реализации для PHP 4 есть одна тонкость.

<?php

class SampleClass {  
  function &instance()
  {
    static $instance;
    if (!is_object($instance))
      /*
        ВНИМАНИЕ! Использование оператора =& в данном случае
        будет ошибкой, так как статические переменные реализованы в PHP 4
        при помощи ссылок. Используем простой оператор присвоения:
      */
      $instance = new SampleClass();
    return $instance;
  }
}

Пример использования:

<?php

// Первый вызов статического метода instance() создает экземпляр объекта:
$obj_1 =& SampleClass::instance();

// Все последующие вызовы метода instance возвращают ссылку на тот же самый 
// экземпляр:
$obj_2 =& SampleClass::instance();

?>

Выдача правильного заголовка Content-Length

Хотя размер динамически генерируемой страницы заранее неизвестен, правильный заголовок Content-Length нетрудно получить при помощи обработчика выходного потока.

<?php
function setContentLength($x) {
  header("Content-Length: ".strlen($x));
  return $x;
}
ob_start("setContentLength");

/*
  Код, генерирующий содержимое страницы
*/
?>

Таким способом можно выставлять правильный Content-Length даже для страниц с gzip-сжатием — для этого ob_start("setContentLength"); должен быть вызван перед ob_start("ob_gzhandler");.

Автоопределение URL в строке

Регулярное выражение, отлавливающее большинство URL-адресов, которым могут встретиться в реальной жизни:

<?
define('URL_PATTERN',     '\b(?:'.
                                '(?:[a-z]+://|www\.)(?:[a-z0-9-]+\.)*[a-z0-9]+'.
                                '|'.
                                '(?:[a-z0-9][a-z0-9-]*\.)+(?:ru|com|net|org)(?![\w-])'.
                            ')\S*'.
                            '(?:(?<![[:punct:]])|(?<=[-/&+*]))');
?>

Данное регулярное выражение корректно отлавливает ссылки, не начинающиеся с www. или http://, например, php.net/docs.php. Список доменов первого уровня для таких ссылок жёстко задан (видно непосредственно в коде), но, в принципе, можно заменить ru|com|net|org на что-нибудь вроде [a-z]{2,4}. Правда, при этом сильно возрастёт вероятность ошибок, особенно в текстах компьютерной тематики. В этом случае имеет смысл явно проверять домен на существование.

Если требуется особая точность, но проверять домен на существование нет возможности, то можно воспользоваться следующим массивом

$all_domains=array('com','edu','gov','mil','net','org','info','biz','arpa','ad','ae','af','ag','ai','al','am','an',
    'ao','aq','ar','as','at','au','aw','az','ba','bb','bd','be','bf','bg','bh','bi','bj','bm','bn','bo','br','bs','bt',
    'bv','bw','by','bz','ca','cc','cf','cg','ch','ci','ck','cl','cm','cn','co','cr','cu','cv','cx','cy','cz','de','dj',
    'dk','dm','do','dz','ec','ee','eg','eh','er','es','et','fi','fj','fk','fm','fo','fr','fx','ga','gd','ge','gf','gg',
    'gh','gi','gl','gm','gn','gp','gq','gr','gs','gt','gu','gw','gy','hk','hm','hn','hr','ht','hu','id','ie','il','im',
    'in','io','iq','ir','is','it','je','jm','jo','jp','ke','kg','kh','ki','km','kn','kp','kr','kw','ky','kz','la','lb',
    'lc','li','lk','lr','ls','lt','lu','lv','ly','ma','mc','md','mg','mh','mk','ml','mm','mn','mo','mp','mq','mr','ms',
    'mt','mu','mv','mw','mx','my','mz','na','nc','ne','nf','ng','ni','nl','no','no','np','nr','nu','nz','om','pa','pe',
    'pf','pg','ph','pk','pl','pn','pr','pt','pw','py','qa','re','ro','ru','rw','sa','sb','sc','sd','se','sg','sh','si',
    'sj','sk','sl','sm','sn','so','sr','st','sv','sy','sz','tc','td','tf','tg','th','tj','tk','tm','tn','to','tp','tr',
    'tt','tv','tw','tz','ua','ug','uk','um','us','uy','uz','va','vc','ve','vg','vi','vn','vu','wf','ws','ye','yt','yu',
    'za','zm','zr','zw',
);

База данных доменов верхнего уровня или то же самое в одном текстовом файле.

Замена некоторой подстроки только вне тэгов

<?
$html = 'текст с подстрокой, подверженной <span title="С точки зрения подстроки!">ожирению</span>';
$substring = 'подстро\S+';
$replacement = '<b>$2</b>';
$result = preg_replace("/((?:^|>)[^<]*)($substring)/s", '$1'.$replacement, $html);
?>

Необходимо только учитывать, что HTML-код $html должен быть корректным, а именно — он не должен использовать знаки < и > ни для чего иного, кроме как для ограничения тэгов (их нужно заменять на &lt; и &gt; соответственно, в том числе и в значениях атрибутов). Во многих современных системах так и есть, так что код пригоден, например, для подсветки найденных слов в форумах.

Совет для случая, если $substring является регулярным выражением. В целях ускорения работы очень желательно, чтобы как можно большая часть $substring (в идеале — вся целиком) была заключена в специальные скобки (?>...), запрещающие бэктрекинг в регулярных выражениях. Если эти скобки не использовать, механизм обработки регулярных выражений, не найдя соответствия в части текста вне тэгов, может начать выполнять откаты в поисках совпадений, что далеко не всегда верно. Вообще, старайтесь как можно чаще использовать конструкцию (?>...) там, где это возможно, потому что она значительно ускоряет работу регулярных выражений в случае их несовпадения со строкой. (См. подробности в документации PHP.)

Перекодирование строки UTF-8 в HTML-entities

Для работы с кодировками предназначены функции группы iconv, но, к сожалению, они при перекодировании из юникода в 8-битовые кодировки попросту выбрасывают символы, которые в целевой кодировке отсутствуют.

Если PHP собран с поддержкой multibyte-функций, то для преобразования можно использовать функцию mb_convert_encoding:

<?
mb_convert_encoding($string, 'HTML-ENTITIES', 'UTF-8');
?>

Если же поддержка mb_convert_encoding не гарантирована, то можно использовать следующую универсальную функцию:

<?
function utf2entity($s) {
    // если можем, то используем функцию mb_convert_encoding…
    if (function_exists('mb_convert_encoding')) 
      return mb_convert_encoding($s, 'HTML-ENTITIES', 'UTF-8');

    //… иначе раскодируем UTF вручную
    $tgt = '';
    for($i=0,$len=strlen($s); $i<$len; $i++) {
        $c = $s[$i];
        $x = ord($c);
        if ($x < 0x80) { // 1-байтовый символ
            $tgt .= $c;
            continue;
        } elseif (($x & 0xC0) == 0xC0) { // (n+1)-байтовый символ
            $n = 1;
            while ( ($x & (0x40 >> $n)) > 0) $n++;
            $code = $x & (0x3F >> $n);
            for ($k=1; $k<=$n; $k++) {
                $y = ord($s[$i+$k]) & 0x3F;
                $code = ($code << 6) + $y;
            }
            $i += $n;
            // В переменной $code содержится Unicode-код текущего символа. 
            // Здесь можно преобразовать его в нужную нам 8-битную кодировку 
            // или просто сделать из него HTML-entity.
            $tgt .= '&#x'.dechex($code).';';
        } else {
            $tgt .= '?'; // такого не должно быть
        }
    }
    return $tgt;
}
?>

Определение корректности UTF-8-строк

<?
function utf8_compliant($str) {
    if ( strlen($str) == 0 ) return true;
    return (preg_match('/^.{1}/us',$str) == 1);
}
?>

Модификатор /u — флаг того, что обрабатывается UTF-8-строка. Если строка в целом не является корректной UTF-8-строкой, то любой паттерн с таким модификатором не даст совпадения (даже если в строке содержатся корректные UTF-8-фрагменты).

Источник — http://www.phpwact.org/php/i18n/charsets?s=utf8.

Поиск по сайту

Подробнее

Склонение существительных с числительными

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

<?
function pluralForm($n, $form1, $form2, $form5)
{
    $n = abs($n) % 100;
    $n1 = $n % 10;
    if ($n > 10 && $n < 20) return $form5;
    if ($n1 > 1 && $n1 < 5) return $form2;
    if ($n1 == 1) return $form1;
    return $form5;
}

// пример использования
echo "В Вашем почтовом ящике $n ".pluralForm($n, "письмо", "письма", "писем");
?>

Перевод чисел в другие системы счисления

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

<?
function custombase_convert_big ($numstring, $frombase, $tobase)
{
   $chars = "0123456789abcdefghijklmnopqrstuvwxyz";
   $tostring = substr($chars, 0, $tobase);
   $numstring = strtolower($numstring);
   $length = strlen($numstring);

   $number = array();
   for ($i = 0; $i < $length; $i++) {
      $number[$i] = strpos($chars, $numstring{$i});
   }

   $result = '';
   do {
      $divide = 0;
      $newlen = 0;
      for ($i = 0; $i < $length; $i++) {
         $divide = $divide * $frombase + $number[$i];
         if ($divide >= $tobase) {
            $number[$newlen++] = (int) ($divide / $tobase);
            $divide = $divide % $tobase;
         } elseif ($newlen > 0) {
            $number[$newlen++] = 0;
         }
      }
      $length = $newlen;
      $result = $tostring{$divide} . $result;
   } while ($newlen != 0);
   return $result;
}
?>
Powered by POEM™ Engine Copyright © 2002-2005