Готовые решения
Оглавление
- Кэширование результата функции в static-переменной
- Реализация паттерна "Одиночка" (Singleton) для PHP 4
- Выдача правильного заголовка Content-Length
- Автоопределение URL в строке
- Замена некоторой подстроки только вне тэгов
- Перекодирование строки UTF-8 в HTML-entities
- Определение корректности UTF-8-строк
- Поиск по сайту
- Склонение существительных с числительными
- Перевод чисел в другие системы счисления
Кэширование результата функции в 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 должен быть корректным, а именно — он не должен использовать знаки < и > ни для чего иного, кроме как для ограничения тэгов (их нужно заменять на < и > соответственно, в том числе и в значениях атрибутов). Во многих современных системах так и есть, так что код пригоден, например, для подсветки найденных слов в форумах.
Совет для случая, если $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;
}
?>
![[logo]](/site/images/logo.jpg)