php5.com.ua - мы знаем о PHP все http://www.php5.com.ua ru info@php5.com.ua php5.com.ua - мы знаем о PHP все <![CDATA[Чем PHP 5.4 отличается от PHP 5.x]]> http://www.php5.com.ua/blog/php-programming/202.html http://www.php5.com.ua/blog/php-programming/202.html /** * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann * (http://qbnz.com/highlighter/ and http://geshi.org/) */ .php.php {color: #000066; border: 1px solid #d0d0d0; background-color: #f0f0f0;} .php.php a:link {color: #000060;} .php.php a:hover {background-color: #f0f000;} .php.php .imp {font-weight: bold; color: red;} .php.php .kw1 {color: #b1b100;} .php.php .kw2 {color: #000000; font-weight: bold;} .php.php .kw3 {color: #990000;} .php.php .co1 {color: #666666; font-style: italic;} .php.php .co2 {color: #666666; font-style: italic;} .php.php .co3 {color: #0000cc; font-style: italic;} .php.php .co4 {color: #0000ff; font-style: italic;} .php.php .coMULTI {color: #666666; font-style: italic;} .php.php .es_h {color: #000099; font-weight: bold;} .php.php .es_h {color: #000099; font-weight: bold;} .php.php .br0 {color: #009900;} .php.php .sy0 {color: #339933;} .php.php .st0 {color: #0000ff;} .php.php .st_h {color: #0000ff;} .php.php .nu0 {color: #cc66cc;} .php.php .nu8 {color: #208080;} .php.php .nu12 {color: #208080;} .php.php .nu19 {color:#800080;} .php.php .me1 {color: #004000;} .php.php .me2 {color: #004000;} .php.php .re0 {color: #000088;} .php.php span.xtra { display:block; }

Добавлена поддержка трейтов.


Начиная с версии 5.4.0 PHP вводит инструментарий для повторного использования кода, называемый трейтом.

Трейт (англ. trait) — это механизм обеспечения повторного использования кода в языках с поддержкой единого наследования, таких как PHP. Трейт предназначен для уменьшения некоторых ограничений единого наследования, позволяя разработчику повторно использовать наборы методов свободно, в нескольких независимых классах и реализованных с использованием разных архитектур построения классов. Семантика комбинации трейтов и классов определена таким образом, чтобы снизить уровень сложности, а также избежать типичных проблем, связанных с множественным наследованием и c т.н. mixins.

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

Пример #1 Пример использования трейта

<?php
trait ezcReflectionReturnInfo {
    function getReturnType() { /*1*/ }
    function getReturnDescription() { /*2*/ }
}

class ezcReflectionMethod extends ReflectionMethod {
    use ezcReflectionReturnInfo;
    /* ... */
}

class ezcReflectionFunction extends ReflectionFunction {
    use ezcReflectionReturnInfo;
    /* ... */
}
?>
 


Добавлен короткий синтаксис объявления массивов.


Например,
$a = [1, 2, 3, 4]; или $a = ['one' => 1, 'two' => 2, 'three' => 3, 'four' => 4];


Добавлена возможность разыменования массивов, возвращаемых функциями.


Например:
foo()[0]
.

Классы для создания анонимных функций


(Closures) теперь поддерживают $this.
Анонимные функции, также известные как замыкания (closures), позволяют создавать функции, не имеющие определенных имен. Они наиболее полезны в качестве значений callback-параметров, но также могут иметь и множество других применений.

<?php
echo preg_replace_callback('~-([a-z])~', function ($match) {
    return strtoupper($match[1]);
}, 'hello-world');
// выведет helloWorld
?>


Оператор <?= теперь доступен всегда, несмотря на значение php.ini опции short_open_tag.



Добавлена возможность получения доступа к члену класса при создании экземпляра.


Например:
(new Foo)->bar()


Теперь поддерживается такой синтаксис:

Class::{expr}()

Добавлен бинарный формат задания чисел


например:
0b001001101

Улучшены сообщения об ошибках разбора и предупреждения о несовместимых аргументах.


Расширение по работе с сессиями теперь может отслеживать процесс загрузки файлов.


Встроенный веб-сервер в режиме командной строки для разработчиков.

]]>
Thu, 19 Apr 2012 11:12:06 +0300 igorok php
<![CDATA[Продается сайт w2.com.ua]]> http://www.php5.com.ua/blog/php-programming/189.html http://www.php5.com.ua/blog/php-programming/189.html /** * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann * (http://qbnz.com/highlighter/ and http://geshi.org/) */ .php.php {color: #000066; border: 1px solid #d0d0d0; background-color: #f0f0f0;} .php.php a:link {color: #000060;} .php.php a:hover {background-color: #f0f000;} .php.php .imp {font-weight: bold; color: red;} .php.php .kw1 {color: #b1b100;} .php.php .kw2 {color: #000000; font-weight: bold;} .php.php .kw3 {color: #990000;} .php.php .co1 {color: #666666; font-style: italic;} .php.php .co2 {color: #666666; font-style: italic;} .php.php .co3 {color: #0000cc; font-style: italic;} .php.php .co4 {color: #0000ff; font-style: italic;} .php.php .coMULTI {color: #666666; font-style: italic;} .php.php .es_h {color: #000099; font-weight: bold;} .php.php .es_h {color: #000099; font-weight: bold;} .php.php .br0 {color: #009900;} .php.php .sy0 {color: #339933;} .php.php .st0 {color: #0000ff;} .php.php .st_h {color: #0000ff;} .php.php .nu0 {color: #cc66cc;} .php.php .nu8 {color: #208080;} .php.php .nu12 {color: #208080;} .php.php .nu19 {color:#800080;} .php.php .me1 {color: #004000;} .php.php .me2 {color: #004000;} .php.php .re0 {color: #000088;} .php.php span.xtra { display:block; }
Ко мне обратился мой товарищ с просьбой разместить объявление о продаже его детища. Долгое время он поддерживал данный ресурс своим сайтом и с него шел отличный трафик. Ниже объявление:


Добрый день, уважаемые читатели.

Продаю сайт http://w2.com.ua/

Долгое время я и команда единомышленников поддерживали его, за время существования с 2007 года, проект стал одним из самых посещаемых блогов об интернете в Украине.

Сейчас настало время, когда мы хотим сосредоточится на других проектах. А http://w2.com.ua/ отдать тому, кто сможет сделать его еще лучше.

Это совершенно не значит что если я его не продам, то закрою. Мы и дальше будем его поддерживать. Просто мы утратили былой интерес и я верю найдется человек который сможет вывести его на совершенно новый уровень, сделать его интересней.

О сайте

Web 2.0 magazine — интернет издание, ежедневно рассказывающее о событиях в мире Веб 2.0, о социальных сетях и стартапах, о слияних& поглощениях, внутренностях больших и маленьких компаний, а также, о многом-многом другом из жизни Веба нового поколения.

На сегодняшний день на сайте зарегистрировано более 10 тыс. пользователей.

Сайт посещает более 2500 человек в день (см. статистику Bigmir).

Технические требования: PHP, MySQL.

Цена

Я хочу получить за сайт $3000, цену готов обсуждать. Сайт приносит небольшой, но все же доход.

Основной проблемой является отсутствие времени. Из-за этого нет возможности плотнее работать с аудиторией. Брать интервью, выступать с аналитическими докладами на barcamp, привлекать новых авторов.

Как связаться

Mail — info@w2.com.ua
Телефон — +380 98 692 77 98 (на этот номер смс не приходят, только звонить)
Skype -andrei.vasiliadi

Спасибо за внимание!
Буду благодарен если Вы расскажете своим друзьям, кому проект может быть интересен, а он своим.]]>
Fri, 11 Feb 2011 00:06:45 +0200 igorok объявление
<![CDATA[Асинхронность с помощью fastcgi_finish_request()]]> http://www.php5.com.ua/blog/php-programming/148.html http://www.php5.com.ua/blog/php-programming/148.html /** * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann * (http://qbnz.com/highlighter/ and http://geshi.org/) */ .php.php {color: #000066; border: 1px solid #d0d0d0; background-color: #f0f0f0;} .php.php a:link {color: #000060;} .php.php a:hover {background-color: #f0f000;} .php.php .imp {font-weight: bold; color: red;} .php.php .kw1 {color: #b1b100;} .php.php .kw2 {color: #000000; font-weight: bold;} .php.php .kw3 {color: #990000;} .php.php .co1 {color: #666666; font-style: italic;} .php.php .co2 {color: #666666; font-style: italic;} .php.php .co3 {color: #0000cc; font-style: italic;} .php.php .co4 {color: #0000ff; font-style: italic;} .php.php .coMULTI {color: #666666; font-style: italic;} .php.php .es_h {color: #000099; font-weight: bold;} .php.php .es_h {color: #000099; font-weight: bold;} .php.php .br0 {color: #009900;} .php.php .sy0 {color: #339933;} .php.php .st0 {color: #0000ff;} .php.php .st_h {color: #0000ff;} .php.php .nu0 {color: #cc66cc;} .php.php .nu8 {color: #208080;} .php.php .nu12 {color: #208080;} .php.php .nu19 {color:#800080;} .php.php .me1 {color: #004000;} .php.php .me2 {color: #004000;} .php.php .re0 {color: #000088;} .php.php span.xtra { display:block; } При оптимизации приложения важно не забывать о том, что оптимизируем мы прежде всего для клиента. Сайт, который работает медленно, это всегда неудобно и плохо.

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

Одна из распространенных практик — это переводить необязательную для ответа часть логики в асинхронную обработку. Для этой задачи применяются очереди сообщений.

Если Вы счастливый обладатель связки PHP + PHP-FPM, то существует более простой (хотя и несколько ограниченный) подход для реализации асинхронности. После сборки патча php-fpm, Вам станет доступна функция:

fastcgi_finish_request();

После ее вызова из скрипта, php-fpm получает сигнал о завершении запроса (т.е. отправляет ответ Web серверу), но сам скрипт не завершается. Т.е. вся логика, которая находится после вызова этой функции будет выполнена на фоне.

Для примера рассмотрим задачу отправки письма (зачастую, весьма медленный процесс):

$to = $_POST['to'];
$body = $_POST['body'];
$subject = $_POST['subject'];

if ( $to && $body && $subject )
{
        echo 'Ваше письмо успешно отправлено';
        # После этой инструкции посетителю уйдет ответ
        fastcgi_finish_request();
        # Сама отправка будет выполнена на фоне
        mail($to, $subject, $body);
}
else
{
        echo 'Вы не ввели все необходимые данные';
}

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

Вам приходилось пользоваться fastcgi_finish_request(), и если да, то в каких случаях?]]>
Tue, 22 Dec 2009 11:33:47 +0200 igorok оптимизация php fastcgi
<![CDATA[Переход от php4 к php5 (Статические члены класса. Исключения, определённые пользователем. Пространства имен)]]> http://www.php5.com.ua/blog/php-programming/146.html http://www.php5.com.ua/blog/php-programming/146.html /** * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann * (http://qbnz.com/highlighter/ and http://geshi.org/) */ .php.php {color: #000066; border: 1px solid #d0d0d0; background-color: #f0f0f0;} .php.php a:link {color: #000060;} .php.php a:hover {background-color: #f0f000;} .php.php .imp {font-weight: bold; color: red;} .php.php .kw1 {color: #b1b100;} .php.php .kw2 {color: #000000; font-weight: bold;} .php.php .kw3 {color: #990000;} .php.php .co1 {color: #666666; font-style: italic;} .php.php .co2 {color: #666666; font-style: italic;} .php.php .co3 {color: #0000cc; font-style: italic;} .php.php .co4 {color: #0000ff; font-style: italic;} .php.php .coMULTI {color: #666666; font-style: italic;} .php.php .es_h {color: #000099; font-weight: bold;} .php.php .es_h {color: #000099; font-weight: bold;} .php.php .br0 {color: #009900;} .php.php .sy0 {color: #339933;} .php.php .st0 {color: #0000ff;} .php.php .st_h {color: #0000ff;} .php.php .nu0 {color: #cc66cc;} .php.php .nu8 {color: #208080;} .php.php .nu12 {color: #208080;} .php.php .nu19 {color:#800080;} .php.php .me1 {color: #004000;} .php.php .me2 {color: #004000;} .php.php .re0 {color: #000088;} .php.php span.xtra { display:block; } Начало:
http://php5.com.ua/blog/php-programming/133.html
http://php5.com.ua/blog/php-programming/134.html
http://php5.com.ua/blog/php-programming/135.html

Статические члены класса


Статические члены и статические методы могут использоваться для реализации того, что в ООП называется «методы класса» и «переменные класса».

«Статическим методом класса» называют метод, который можно вызвать без создания объекта этого класса.
«Переменной класса» называют переменную, к которой можно обратиться без создания объекта этого класса (и метод доступа при этом не потребуется).

Пример: методы класса и переменные класса
<?php
class calculator {
  static public $pi = 3.14151692;

  static public function add($x,$y) {
    return $x + $y;
  }
}

$s = calculator::$pi;
$result = calculator::add(3,7);
print("$result");
?>

Исключения — это общепринятый подход к обработке ошибок и неожиданных ситуаций в таких языках как Java и C++; в PHP5 перехват исключений реализован с помощью пары «try» — «catch».

Пример: Исключения
<?php class foo {

  function divide($x,$y) {
    if($y==0) throw new Exception("деление на ноль недопустимо");
    return $x/$y;
  }
}

$x = new foo();

try {
  $x->divide(3,0);  
} catch (Exception $e) {
    echo $e->getMessage();
    echo "\n<br />\n";
    // Какие-нибудь драконовские меры
}
?>


Как вы видите, «try» используется для обозначения блока, в котором находятся ошибки, обрабатываемые оператором «catch», стоящим в конце блока. В блоке «catch» вам нужно реализовать вашу собственную политику обработки ошибок. В итоге получаем удобочитаемый код и всего один блок обработки ошибок.

Исключения, определённые пользователем


Для обработки непредвиденных проблем в ваших программах вы можете определить ваши собственные исключения. Всё, что вам нужно — это просто дополнить (extend) класс Exception, определив конструктор класса и метод getMessage.

Пример: Исключения, определённые пользователем

<?php
class WeirdProblem extends Exception {

   private $data;

   function WeirdProblem($data) {
        parent::exception();
        $this->data = $data;
    }

    function getMessage() {
        return $this->data . " вызвало какое-то странное исключение!";
    }
}
?>


Потом, для возбуждения определённого вами исключения используйте конструкцию throw new WeirdProblem($foo); если исключение происходит внутри блока try{}, то PHP5 передаст управление в «catch»-блок для обработки.

Пространства имён


В целях удобства классы и функции могут быть сгруппированы в пространства имён (namespaces).

Примечение: разработчики отказались от поддрежки этой возможности.

Пример: Пространство имён
<?php
namespace Math {

  class Complex {
    //...код...
    function __construct() {
      print("привет");
    }
  }
}

$m = new Math::Complex();
?>

Обратите внимание на синтаксис использования именного пространства для обозначения класса, объект которого мы создаём. Пример практического применения: создание одноимённых классов в разных именных пространствах; при этом классы делают отличную друг от друга работу (имея одинаковый интерфейс).]]>
Fri, 18 Dec 2009 11:33:39 +0200 igorok php try ошибки исключения static class
<![CDATA[Переход от php4 к php5 ( Абстрактные классы. __set и __get)]]> http://www.php5.com.ua/blog/php-programming/135.html http://www.php5.com.ua/blog/php-programming/135.html /** * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann * (http://qbnz.com/highlighter/ and http://geshi.org/) */ .php.php {color: #000066; border: 1px solid #d0d0d0; background-color: #f0f0f0;} .php.php a:link {color: #000060;} .php.php a:hover {background-color: #f0f000;} .php.php .imp {font-weight: bold; color: red;} .php.php .kw1 {color: #b1b100;} .php.php .kw2 {color: #000000; font-weight: bold;} .php.php .kw3 {color: #990000;} .php.php .co1 {color: #666666; font-style: italic;} .php.php .co2 {color: #666666; font-style: italic;} .php.php .co3 {color: #0000cc; font-style: italic;} .php.php .co4 {color: #0000ff; font-style: italic;} .php.php .coMULTI {color: #666666; font-style: italic;} .php.php .es_h {color: #000099; font-weight: bold;} .php.php .es_h {color: #000099; font-weight: bold;} .php.php .br0 {color: #009900;} .php.php .sy0 {color: #339933;} .php.php .st0 {color: #0000ff;} .php.php .st_h {color: #0000ff;} .php.php .nu0 {color: #cc66cc;} .php.php .nu8 {color: #208080;} .php.php .nu12 {color: #208080;} .php.php .nu19 {color:#800080;} .php.php .me1 {color: #004000;} .php.php .me2 {color: #004000;} .php.php .re0 {color: #000088;} .php.php span.xtra { display:block; } Начало:
http://php5.com.ua/blog/php-programming/133.html
http://php5.com.ua/blog/php-programming/134.html

Абстрактные классы


Абстрактным называется класс, который может использоваться только как базовый (то есть создавать объекты этого класса нельзя). Как и в любом нормальном базовом классе, в абстрактном классе вы можете определять методы и переменные.

В абстрактном классе также можно определять абстрактные методы: методы, которые не реализованы в абстрактном классе, но которые обязательно должны быть реализованы в производных классах.

Пример: Абстрактные классы
<?php
abstract class foo {
  protected $x;

  abstract function display();

  function setX($x) {
    $this->x = $x;
  }
}


class foo2 extends foo {
  function display() {
    // Код
  }
}
?>

__call

С PHP5 вы можете реализовать в классе специальный метод __call(), как метод для «отлова» всех нереализованных в данном классе методов. Метод __call (если он определён) вызывается при попытке вызвать недоступный или несуществующий метод.

Пример: __call
<?php
class foo {

  function __call($name,$arguments) {
    print("Вызывали? Я -  $name!");
  }
}

$x = new foo();
$x->doStuff();
$x->fancy_stuff();
?>

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

Пример: Перегрузка методов с помощью __call
<?php
class Magic {

  function __call($name,$arguments) {
    if($name=='foo') {
      if(is_int($arguments[0])) $this->foo_for_int($arguments[0]);
      if(is_string($arguments[0])) $this->foo_for_string($arguments[0]);
    }
  }

  private function foo_for_int($x) {
    print("у, смотрите, целое число!");
  }

  private function foo_for_string($x) {
    print("у, смотрите, строка!");
  }
}

$x = new Magic();
$x->foo(3);
$x->foo("3");
?>

__set и __get


Но это ещё не всё, теперь вы можете определить методы __set и __get для «отлова» всех попыток изменения или доступа к неопределённым (или недоступным) переменным.

Пример: __set и __get
<?php
class foo {

  function __set($name,$val) {
    print("Привет, вы попытались присвоить значение $val переменной $name");
  }

  function __get($name) {
    print("Привет, вы пытались обратиться к $name");
  }
}

$x = new foo();
$x->bar = 3;
print($x->winky_winky);
?>

В PHP5 вы сможете «сказать» методу, что он должен получить в качестве аргумента объект определённого типа.

Пример: указание типов
<?php
class foo {
  // код ...
}

class bar {
  public function process_a_foo(foo $foo) {
   // Ещё какой-нибудь код
  }
}

$b = new bar();
$f = new foo();
$b->process_a_foo($f);
?>

Как вы заметили, перед именем аргумента теперь можно поставить имя его класса, и таким образом PHP5 определит, что переменная $foo должна быть класса foo.

Продолжение:
http://php5.com.ua/blog/php-programming/146.html]]>
Thu, 05 Nov 2009 18:41:04 +0200 igorok php абстрактные классы set get
<![CDATA[Переход от php4 к php5 (Дескрипторы Private, Public и Protected. Интерфейсы)]]> http://www.php5.com.ua/blog/php-programming/134.html http://www.php5.com.ua/blog/php-programming/134.html /** * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann * (http://qbnz.com/highlighter/ and http://geshi.org/) */ .php.php {color: #000066; border: 1px solid #d0d0d0; background-color: #f0f0f0;} .php.php a:link {color: #000060;} .php.php a:hover {background-color: #f0f000;} .php.php .imp {font-weight: bold; color: red;} .php.php .kw1 {color: #b1b100;} .php.php .kw2 {color: #000000; font-weight: bold;} .php.php .kw3 {color: #990000;} .php.php .co1 {color: #666666; font-style: italic;} .php.php .co2 {color: #666666; font-style: italic;} .php.php .co3 {color: #0000cc; font-style: italic;} .php.php .co4 {color: #0000ff; font-style: italic;} .php.php .coMULTI {color: #666666; font-style: italic;} .php.php .es_h {color: #000099; font-weight: bold;} .php.php .es_h {color: #000099; font-weight: bold;} .php.php .br0 {color: #009900;} .php.php .sy0 {color: #339933;} .php.php .st0 {color: #0000ff;} .php.php .st_h {color: #0000ff;} .php.php .nu0 {color: #cc66cc;} .php.php .nu8 {color: #208080;} .php.php .nu12 {color: #208080;} .php.php .nu19 {color:#800080;} .php.php .me1 {color: #004000;} .php.php .me2 {color: #004000;} .php.php .re0 {color: #000088;} .php.php span.xtra { display:block; } Начало здесь: http://php5.com.ua/blog/php-programming/133.html

Дескрипторы Private, Public и Protected


В PHP4 все методы и переменные внутри объекта были доступны извне, другими словами все методы и переменные всегда были открытыми. В PHP5 вводится три дескриптора для осуществления контроля над доступом к переменным и методам: Public, Protected и Private.

* Public (открытый): Метод/переменная доступны из любого места в коде.
* Private (закрытый): Закрытые методы или переменные доступны только внутри класса.
* Protected (защищённый): Защищённые методы или переменные доступны только внутри класса, где они были объявлены и из его производных классов.

Пример: Public, protected and private

<?php
class foo {
  private $x;

  public function public_foo() {
    print("Это открытый метод");
  }

  protected function protected_foo() {
    $this->private_foo(); //Всё правильно, мы можем вызывать закрытые методы, потому что мы находимся в том же классе
    print("Это защищённый метод");
  }

  private function private_foo() {
    $this->x = 3;
    print("Это закрытый метод");
  }
}

class foo2 extends foo {
  public function display() {
    $this->protected_foo();
    $this->public_foo();
    // $this->private_foo();  // Неправильно! В базовом классе метод закрыт
  }
}

$x = new foo();
$x->public_foo();
//$x->protected_foo();  //Неправильно, защищённые методы могут вызываться только из того же класса или
//его производных классов
//$x->private_foo();    //Неправильно, закрытые методы могут быть вызваны только в классе, где они были объявлены

$x2 = new foo2();
$x2->display();
?>


Совет разработчикам: Переменные класса всегда следует делать закрытыми, прямой доступ к переменным — не очень хорошая практика в ООП, лучше всего для доступа/изменения переменных класса определять специальные методы.

Интерфейсы



Как вы знаете, PHP4 поддерживает наследование классов синтаксисом «class foo extends parent». В PHP4 И в PHP5 класс может наследовать только один класс, то есть множественное наследование не поддерживается. Интерфейсом называется класс, в котором не реализуется ни один метод, определяются только названия методов и набор передаваемых им параметров. Впоследствии классы могут 'реализовывать' сколь угодно много интерфейсов, показывая тем самым, что тот или иной класс реализует методы, определённые в интерфейсе.

Пример: Интерфейсы

<?php
interface displayable {
  function display();
}

interface printable {
  function doprint();
}

class foo implements displayable,printable {
  function display() {
    // код
  }

  function doprint() {
    // код
  }
}
?>


Использование интерфейсов полезно для более удобного чтения и понимания кода: прочитав объявление класса, мы увидим, что класс реализует интерфейсы displayable и printable; это означает, что класс должен иметь методы display() и doprint(). Как эти методы реализованы — значения не имеет, главное — уже из объявления класса, вы знаете, что можете вызывать эти методы.

Продолжение:
http://php5.com.ua/blog/php-programming/135.html
http://php5.com.ua/blog/php-programming/146.html]]>
Fri, 23 Oct 2009 09:59:18 +0300 igorok php дескрипторы интерфейсы
<![CDATA[Переход от php4 к php5]]> http://www.php5.com.ua/blog/php-programming/133.html http://www.php5.com.ua/blog/php-programming/133.html /** * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann * (http://qbnz.com/highlighter/ and http://geshi.org/) */ .php.php {color: #000066; border: 1px solid #d0d0d0; background-color: #f0f0f0;} .php.php a:link {color: #000060;} .php.php a:hover {background-color: #f0f000;} .php.php .imp {font-weight: bold; color: red;} .php.php .kw1 {color: #b1b100;} .php.php .kw2 {color: #000000; font-weight: bold;} .php.php .kw3 {color: #990000;} .php.php .co1 {color: #666666; font-style: italic;} .php.php .co2 {color: #666666; font-style: italic;} .php.php .co3 {color: #0000cc; font-style: italic;} .php.php .co4 {color: #0000ff; font-style: italic;} .php.php .coMULTI {color: #666666; font-style: italic;} .php.php .es_h {color: #000099; font-weight: bold;} .php.php .es_h {color: #000099; font-weight: bold;} .php.php .br0 {color: #009900;} .php.php .sy0 {color: #339933;} .php.php .st0 {color: #0000ff;} .php.php .st_h {color: #0000ff;} .php.php .nu0 {color: #cc66cc;} .php.php .nu8 {color: #208080;} .php.php .nu12 {color: #208080;} .php.php .nu19 {color:#800080;} .php.php .me1 {color: #004000;} .php.php .me2 {color: #004000;} .php.php .re0 {color: #000088;} .php.php span.xtra { display:block; }

Переход к PHP5


Краткий обзор возможностей PHP по материалам PHP 5 beta 3.
PHP, фактически, является самым распостраненным языком для Web программирования. В достижении этого статуса он прошел множество этапов, от простого языка для Web программирования который уступал многим (php3), до сегодняшнего быстрого мощного и расширяемого (PHP4). Тем более приятно, что PHP не стоит на месте и продолжает развиваться оставаясь таким-же простым для начинающих и предоставляя все больше возможностей более квалифицированным разработчикам.

Введение

PHP, фактически, является самым распостраненным языком для Web программирования. В достижении этого статуса он прошел множество этапов, от простого языка для Web программирования который уступал многим (php3), до сегодняшнего быстрого мощного и расширяемого (PHP4). Тем более приятно, что PHP не стоит на месте и продолжает развиваться оставаясь таким-же простым для начинающих и предоставляя все больше возможностей более квалифицированным разработчикам. В предверьи выхода PHP5 появляется множество информации о улучшениях в PHP 5, включая информацию от самих разработчиков. Например, замечательная статья от одного из авторов Zend Engine — Zeev Suraski (http://phpclub.ru/detail/article/2004-01-07) и её перевод на phpclub.ru очень помогут в понимании тонкостей изменения работы с объектами. Существуют, конечно, и общие обзоры возможностей PHP5, сделанные как отечественными так и зарубежными авторами. В своем обзоре я попытался дать наиболее полное представление о изменениях в PHP5, на сколько это возможно. Эта статья также является в некотором роде «отчетом о проделанной работе», поскольку обзор каждого изменения собровождался детальным его изучением и попыткой использовать на практике.

На этом заканчиваем введение и приступаем к основной части.

Новые уровни доступа private и public

В PHP5 добавлены новые модификаторы уровня доступа для переменных классов. Как и во многих других языках программирования, они носят названия private, protected и public.

Private — самый ограниченничивающий модификатор. Private переменная класса может быть использованна только в классе, в котором объявленна. К ней невозможно обратиться из другого программного кода.

Protected — расширение области private, добавляющее к ней возможность обращаться к переменной из классов-потомков.

Public — расширяющий protected модификатор, задающий наиболее широкую область доступа. К возможности использовать переменную в классах-потомках, добавляется возможность обращаться к переменной непосредственно из другого кода. Строго говоря, public не является новой областью доступа. Ранее в PHP все переменные классов являлись public переменными.

Private переменные используются для алгоритмов, которые используются только в текущем классе и не могут быть переопределенны в классах-потомках. Protected может быть использован, когда организовывается семейство объектов, обладающих сходными алгоритмами и организованных в иерархию. Использование public переменных, обычно, не является хорошей практикой но иногда оправданно. Их можно использовать, если у класса много свойств, которые должны быть доступны всем алгоритмам, использующим этот класс.

Аналогично, private/protected/public мидификаторы применяются к методам класса. Методы, объявленные без модификатора, являются public методами.

Если метод или переменная переопределяются в классе-наследнике, то уровень доступа должен быть таким-же или выше. Например, protected метод в классе-потомке можно сделать public, но нельзя private.

Для примера рассмотрим классы NewClass и NewClass1.

class NewClass {
// new PHP5 modifiers
private $myPrivateVar = 'myPrivateVar';
protected $myProtectedVar = 'myProtectedVar';
public $myPublicVar = 'myPublicVar';
// old PHP declaration
var $myVar = 'myVar';
}

class NewClass1 extends NewClass {
function getProtectedVar() {
return $this->myProtectedVar;
}
}


NewClass содержит несколько переменных с разными областями доступа. NewClass1 используется для тестирования областей видимости, связанных с наследованием.

Создаем объекты классов:

$c = new NewClass();
$c1 = new NewClass1();


Обращаемся к переменным:
print $c->myPrivateVar;

Непосредственное обращение к private переменной приводит к ошибке.
print $c->myProtectedVar;

Непосредственное обращение к protected переменной приводит к ошибке.
print $c->myPublicVar;

Обращение к public переменной возвращает её значение.
print $c->myVar;

Обращение к переменной, объявленной в старом стиле, равносильно обращению к public переменной.
print $c1->myPrivateVar;

Private переменная не была унаследованна классом NewClass1. Обращение к ней равнозначно обращению к необъявленной переменной.
print $c1->myProtectedVar;

Protected переменная была унаследованна и непосредственное обращение к ней приводит к ошибке. Для проверки, что она была унаследованна вместе с начальным значением, можно вызвать «print $c1->getProtectedVar();».
print $c1->myPublicVar;
Public переменная была унаследованна и обращение к ней возвращает её значение.

Продолжение:
http://php5.com.ua/blog/php-programming/134.html
http://php5.com.ua/blog/php-programming/135.html
http://php5.com.ua/blog/php-programming/146.html]]>
Fri, 16 Oct 2009 13:52:49 +0300 igorok php программирование
<![CDATA[Кто поедет из Киева на конфу по php в Москве?]]> http://www.php5.com.ua/blog/php-programming/120.html http://www.php5.com.ua/blog/php-programming/120.html
Я бы съездил.

Подробнее здесь: http://www.phpconf.ru/]]>
Wed, 26 Aug 2009 12:06:59 +0300 igorok конференция
<![CDATA[Парсим линки на PHP]]> http://www.php5.com.ua/blog/php-programming/113.html http://www.php5.com.ua/blog/php-programming/113.html /** * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann * (http://qbnz.com/highlighter/ and http://geshi.org/) */ .php.php {color: #000066; border: 1px solid #d0d0d0; background-color: #f0f0f0;} .php.php a:link {color: #000060;} .php.php a:hover {background-color: #f0f000;} .php.php .imp {font-weight: bold; color: red;} .php.php .kw1 {color: #b1b100;} .php.php .kw2 {color: #000000; font-weight: bold;} .php.php .kw3 {color: #990000;} .php.php .co1 {color: #666666; font-style: italic;} .php.php .co2 {color: #666666; font-style: italic;} .php.php .co3 {color: #0000cc; font-style: italic;} .php.php .co4 {color: #0000ff; font-style: italic;} .php.php .coMULTI {color: #666666; font-style: italic;} .php.php .es_h {color: #000099; font-weight: bold;} .php.php .es_h {color: #000099; font-weight: bold;} .php.php .br0 {color: #009900;} .php.php .sy0 {color: #339933;} .php.php .st0 {color: #0000ff;} .php.php .st_h {color: #0000ff;} .php.php .nu0 {color: #cc66cc;} .php.php .nu8 {color: #208080;} .php.php .nu12 {color: #208080;} .php.php .nu19 {color:#800080;} .php.php .me1 {color: #004000;} .php.php .me2 {color: #004000;} .php.php .re0 {color: #000088;} .php.php span.xtra { display:block; } Такое всегда должно быть под рукой:
$url = "http://artlebedev.kiev.ua/";
$input = @file_get_contents($url) or die('Could not access file: ' . $url);
$regexp = "<a\s[^>]*href=(\"??)([^\" >]*?)\\1[^>]*>(.*)<\/a>";
if(preg_match_all("/$regexp/siU", $input, $matches)) {
   foreach($matches as $match) {
      # $match[2] = link address
      # $match[3] = link text
   }
}


have fun:)]]>
Tue, 28 Jul 2009 18:08:42 +0300 igorok парсер php
<![CDATA[Хранение иерархических данных в БД]]> http://www.php5.com.ua/blog/php-programming/95.html http://www.php5.com.ua/blog/php-programming/95.html /** * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann * (http://qbnz.com/highlighter/ and http://geshi.org/) */ .php.php {color: #000066; border: 1px solid #d0d0d0; background-color: #f0f0f0;} .php.php a:link {color: #000060;} .php.php a:hover {background-color: #f0f000;} .php.php .imp {font-weight: bold; color: red;} .php.php .kw1 {color: #b1b100;} .php.php .kw2 {color: #000000; font-weight: bold;} .php.php .kw3 {color: #990000;} .php.php .co1 {color: #666666; font-style: italic;} .php.php .co2 {color: #666666; font-style: italic;} .php.php .co3 {color: #0000cc; font-style: italic;} .php.php .co4 {color: #0000ff; font-style: italic;} .php.php .coMULTI {color: #666666; font-style: italic;} .php.php .es_h {color: #000099; font-weight: bold;} .php.php .es_h {color: #000099; font-weight: bold;} .php.php .br0 {color: #009900;} .php.php .sy0 {color: #339933;} .php.php .st0 {color: #0000ff;} .php.php .st_h {color: #0000ff;} .php.php .nu0 {color: #cc66cc;} .php.php .nu8 {color: #208080;} .php.php .nu12 {color: #208080;} .php.php .nu19 {color:#800080;} .php.php .me1 {color: #004000;} .php.php .me2 {color: #004000;} .php.php .re0 {color: #000088;} .php.php span.xtra { display:block; }

Модифицированный прямой обход дерева.


Рассмотрим один из методов хранения деревьев. Как правило деревья приходится доставать рекурсивно, что может быть медленно, поэтому рассматривать этот метод не будем. Очень хотелось бы свести к миниму количество запросов к БД, а в идеале к одному запросу:)

Пройдем по нашему дереву горизонтально. Начнем с корня ('Food') и допишем 1 слева. Следующий узел 'Fruit', напишем рядом 2. Таким образом, мы будем ходить вдоль краев дерева и дописывать числа слева и справа каждого узла. Последним, будет номер, справа узла 'Food'. Ниже можно посмотреть на наше пронумерованное дерево со стрелками, указывающими направление обхода.



Мы назовем эти цифры левой и правой (например, левое значение 'Food' — 1, правое — 18). Как видите, эти цифры определяют связь между узлами дерева. Посколькоу 'Red' имеет цифры 3 и 6, он является потомком вершины 1-18 'Food'. В то же время, мы можем сказать, что все вершины у которых левые значения больше 2, а правые меньше 11 являются потомками 2-11 'Fruit'. Таким образом, структура дерева хранится в в левом и правом значениях вершины. Этот метод кругового обхода дерева и подсчета вершин называется 'модифицированный прямой обход дерева'.

Прежде чем продолжить, давайте посмотрим, как это будет храниться у нас в БД:


Слова 'left' и 'right' являются зарезервированными в MySql, поэтому для обозначения столбцов в таблице стоит выбрать другие имена, например, 'lft' и 'rgt' или брать в обратные кавычки. Так же, стоит обратить внимание на то, что нам больше не нужен столбец 'parent'. У нас имеются lft и rgt значения для хранения древовидной структуры.

Получение дерева



Если нам необходимо получить дерево, использующее таблицу с левыми и правыми значениями, то нам для начала нужно будет определиться с узлами, которые нам необходимы. Например, если нам нужен узел 'Fruit' со всеми своими детьми, нам будет достаточно выбрать записи с левыми значениями от 2 до 11.

В таком случае SQL запрос может выглядеть так:
SELECT * FROM tree WHERE lft BETWEEN 2 AND 11;

В результате мы получим:


Все дерево одним запросом. Для того что бы отобразить дерево упорядоченным, как делала это рекурсивная функция добавим в запрос ORDER BY. Если добавлять и удалять записи в таблице, то их порядок нарушится. Поэтому зададим сортировку по левым значениям.

SELECT * FROM tree WHERE lft BETWEEN 2 AND 11 ORDER BY lft ASC;


Единственной проблемой остаются отступы узлов для красивого отображения дерева, т.е. дети должны иметь отступ по отношению к родителю.

Для этого мы будем использовать правые значения наших вершин. Каждый раз, когда мы будем начинать узел с детьми, правое значение это узла мы будем писать в стэк.

You know that all children of that node have a right value that is less than the right value of the parent, so by comparing the right value of the current node with the last right node in the stack, you can see if you're still displaying the children of that parent. Вы знаете, что все дети, что узел имеет право ценность, которая является меньше, чем стоимость права родителей, так что, сравнив права значение текущего узла с последним право узла в стек, можно увидеть, если вы все еще выводить детей этого родителя.

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

<?php
function display_tree($root) {
   // retrieve the left and right value of the $root node
   $result = mysql_query('SELECT lft, rgt FROM tree '.
                          'WHERE title="'.$root.'";');
   $row = mysql_fetch_array($result);

   // start with an empty $right stack
   $right = array();

   // now, retrieve all descendants of the $root node
   $result = mysql_query('SELECT title, lft, rgt FROM tree '.
                          'WHERE lft BETWEEN '.$row['lft'].' AND '.
                          $row['rgt'].' ORDER BY lft ASC;');

   // display each row
   while ($row = mysql_fetch_array($result)) {
       // only check stack if there is one
       if (count($right)>0) {
           // check if we should remove a node from the stack
           while ($right[count($right)-1]<$row['rgt']) {
               array_pop($right);
           }
       }

       // display indented node title
       echo str_repeat('  ',count($right)).$row['title']."\n";

       // add this node to the stack
       $right[] = $row['rgt'];
   }
}
?>


Если запустить этот код, то получим дерево, которое мы получали раньше при помощи рекурсии. Функция получилась на много проще, как если бы писалась рекурсивно и использует только 2 запроса для построения дерева.

Путь к узлу


С этим новым алгоритмом, мы также должны найти новые пути, чтобы получить путь к определенному узлу. Чтобы получить этот путь, нам понадобится список всех предков этого узла. С нашей новой структурой таблицы работы будет не так и много. Если посмотреть, например, на узел 4-5 'Cherry', можно увидеть, что все левые значения предков меньше 4, а все правые — больше 5.

Чтобы получить всех предков, построим следующий запрос:

SELECT title FROM tree WHERE lft < 4 AND rgt > 5 ORDER BY lft ASC;


Как и в предыдущем запросе, мы должны использовать ORDER BY для сортировки узлов.
Запрос вернет:

+-------+
| title |
+-------+
| Food  |
| Fruit |
| Red   |
+-------+


Сейчас мы только объединили записи для получения пути к 'Cherry'.

Подсчет потомков



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

Каждый потомок инкрементирует правое значение узла начиная с 2, тогда количество потомков расчитывается по формуле:

$descendants = ($right$left - 1) / 2;


Исходя из этой простой формулы можно сказать, что 2-11 'Fruit' имеет 4 потомка и что 8-9 'Banana' просто чаилд и не родитель.]]>
Wed, 17 Jun 2009 01:16:36 +0300 igorok деревья рекурсия
<![CDATA[Оптимизируем расположение контента]]> http://www.php5.com.ua/blog/php-programming/96.html http://www.php5.com.ua/blog/php-programming/96.html /** * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann * (http://qbnz.com/highlighter/ and http://geshi.org/) */ .php.php {color: #000066; border: 1px solid #d0d0d0; background-color: #f0f0f0;} .php.php a:link {color: #000060;} .php.php a:hover {background-color: #f0f000;} .php.php .imp {font-weight: bold; color: red;} .php.php .kw1 {color: #b1b100;} .php.php .kw2 {color: #000000; font-weight: bold;} .php.php .kw3 {color: #990000;} .php.php .co1 {color: #666666; font-style: italic;} .php.php .co2 {color: #666666; font-style: italic;} .php.php .co3 {color: #0000cc; font-style: italic;} .php.php .co4 {color: #0000ff; font-style: italic;} .php.php .coMULTI {color: #666666; font-style: italic;} .php.php .es_h {color: #000099; font-weight: bold;} .php.php .es_h {color: #000099; font-weight: bold;} .php.php .br0 {color: #009900;} .php.php .sy0 {color: #339933;} .php.php .st0 {color: #0000ff;} .php.php .st_h {color: #0000ff;} .php.php .nu0 {color: #cc66cc;} .php.php .nu8 {color: #208080;} .php.php .nu12 {color: #208080;} .php.php .nu19 {color:#800080;} .php.php .me1 {color: #004000;} .php.php .me2 {color: #004000;} .php.php .re0 {color: #000088;} .php.php span.xtra { display:block; } Всем известно, что много статического контента, например, картинок, каких-либо файлов, держать в одной папке не кошерно:)
Было бы неплохо разбрасывать контент автоматически по папочкам, например, в зависимости от айдишника единицы контента.

Следующие функции решают эту это проблему:


/**
* Get path for image by ID
* Returns path like /1/2/12 when id = 12
*
* @param int $id
*/

if ( ! function_exists('getPathById')) {
        function getPathById($id) {
                $f1 = $id % 10;
                $f2 = floor(($id % 100) / 10);
                $path = '/' . $f1 . '/' . $f2 . '/' . $id;
                return $path;
        }
}

if ( ! function_exists('makeDirsForID')) {
        function makeDirsForID($id, $path) {
                $f1 = $id % 10;
                if (!file_exists($path . '/' . $f1)) {
                        @mkdir($path . '/' . $f1);
                }
                $f2 = floor(($id % 100) / 10);
                if (!file_exists($path . '/' . $f1 . '/' . $f2)) {
                                @mkdir($path . '/' . $f1 . '/' . $f2);
                }
        }
}

Надеюсь, все понятно и помогло:)]]>
Fri, 12 Jun 2009 17:00:25 +0300 igorok php контент файлы
<![CDATA[Где использовать исключения в php]]> http://www.php5.com.ua/blog/php-programming/85.html http://www.php5.com.ua/blog/php-programming/85.html /** * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann * (http://qbnz.com/highlighter/ and http://geshi.org/) */ .php.php {color: #000066; border: 1px solid #d0d0d0; background-color: #f0f0f0;} .php.php a:link {color: #000060;} .php.php a:hover {background-color: #f0f000;} .php.php .imp {font-weight: bold; color: red;} .php.php .kw1 {color: #b1b100;} .php.php .kw2 {color: #000000; font-weight: bold;} .php.php .kw3 {color: #990000;} .php.php .co1 {color: #666666; font-style: italic;} .php.php .co2 {color: #666666; font-style: italic;} .php.php .co3 {color: #0000cc; font-style: italic;} .php.php .co4 {color: #0000ff; font-style: italic;} .php.php .coMULTI {color: #666666; font-style: italic;} .php.php .es_h {color: #000099; font-weight: bold;} .php.php .es_h {color: #000099; font-weight: bold;} .php.php .br0 {color: #009900;} .php.php .sy0 {color: #339933;} .php.php .st0 {color: #0000ff;} .php.php .st_h {color: #0000ff;} .php.php .nu0 {color: #cc66cc;} .php.php .nu8 {color: #208080;} .php.php .nu12 {color: #208080;} .php.php .nu19 {color:#800080;} .php.php .me1 {color: #004000;} .php.php .me2 {color: #004000;} .php.php .re0 {color: #000088;} .php.php span.xtra { display:block; }

В логике


1. Валидация данных: иными словами ошибка входных данных, формат поля не тот, поле не заполнено, ошибка уникальности поля — всё это ошибки входных данных, в таких случаях я бросаю эксепшн с перечислением всех полей и ошибок, которые в последствии выводятся пользователю.
2. 404 Документ не найден: Если была запрошена конкретная сущность(например строка из бд) по её индефикатору(и не только), то в случае если её нет — бросается эксепшн, который в последствии превращается в страницу 404.
3. 403 Доступ запрещён: Если была попытка доступа пользователя туда, куда ему нельзя — то кидается эксепшн(в аргументах можно передать почему нету туда доступа), который в последствии превращается в 403.
4. 401 Требуется авторизация: Пользователь запрашивает данные, куда нужна авторизация. Выкидываем эксепшн(в аргументах можем передать Relarm — текст запроса авторизации), а пользователь получает либо запрос на HTTP авторизацию, либо обычную формочку.
5. 301 Редирект: Надо редиректнуть? кидаем эксепшн — в нём передаём куда надо редиректить.

При обработке ошибок php


1. Фатальные ошибки: Тут всё понятно, нету коннекта к бд, или конфиг нельзя прочесть. Просто пишем в лог и покзывем дефейс.
2. Критические ошибки: Например: СМСка не отправляется, файл нельзя залить — кидаем специфичный эксепшн. а в нужных местах(например — подтверждение телефона), обрабатываем его и пишем пользователю то что не можем отправить смс.

При отладке


В режиме дебага использую PHP_Exceptionizer. Позволяет сделать код чище, любой нотис и варнинг превращает в эксепшн, что в свою очередь позволяет их не пропустить. Естествено это включено только в дебаг-режиме.

Рекомендую логировать все «непонятые» эксепшены:

class Controller_Front
{
  // на уровне приложения
  public function execute()
  {
    try {
      ...
        // где то на уровне контроллера
        try {
          ... // тут вызов основнного тела контроллера
            // Захотели мы редиректнуть на хабр.
            throw new Controller_RedirectException('http://habr.ru');
          ...
        } catch (Controller_DataException $e) {
          // Сохраняем ошибки и показывем их в шаблоне
          $this->errors = $e->getErrors();
        }
      ...
    } catch (Controller_RedirectException $e) {
      // Метод, который посылает заголовки
      $this->_processRedirectException($e);
    } catch (Controller_AuthException $e) {
      // Метод, запрашивающий HTTP авторизацию
      $this->_processAuthException($e);
    } catch (Exception $e) {
      // Записывем эксепшн в лог.
      $this->_logException($e);
      // Показывем дефейс.
      $this->_processFatalException($e);
    }
  }
}
]]>
Tue, 26 May 2009 10:58:13 +0300 igorok php исключения exception
<![CDATA[Юнит-тестирование контроллеров Zend Framework]]> http://www.php5.com.ua/blog/php-programming/79.html http://www.php5.com.ua/blog/php-programming/79.html /** * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann * (http://qbnz.com/highlighter/ and http://geshi.org/) */ .php.php {color: #000066; border: 1px solid #d0d0d0; background-color: #f0f0f0;} .php.php a:link {color: #000060;} .php.php a:hover {background-color: #f0f000;} .php.php .imp {font-weight: bold; color: red;} .php.php .kw1 {color: #b1b100;} .php.php .kw2 {color: #000000; font-weight: bold;} .php.php .kw3 {color: #990000;} .php.php .co1 {color: #666666; font-style: italic;} .php.php .co2 {color: #666666; font-style: italic;} .php.php .co3 {color: #0000cc; font-style: italic;} .php.php .co4 {color: #0000ff; font-style: italic;} .php.php .coMULTI {color: #666666; font-style: italic;} .php.php .es_h {color: #000099; font-weight: bold;} .php.php .es_h {color: #000099; font-weight: bold;} .php.php .br0 {color: #009900;} .php.php .sy0 {color: #339933;} .php.php .st0 {color: #0000ff;} .php.php .st_h {color: #0000ff;} .php.php .nu0 {color: #cc66cc;} .php.php .nu8 {color: #208080;} .php.php .nu12 {color: #208080;} .php.php .nu19 {color:#800080;} .php.php .me1 {color: #004000;} .php.php .me2 {color: #004000;} .php.php .re0 {color: #000088;} .php.php span.xtra { display:block; } Тестирование Веб-приложений — это комплексная задача, потому что веб-приложение создается из нескольких логических слоев. Модульное тестирование контроллера Zend Framework может быть весьма трудной задачей, особенно для тех, кто слабо знаком с Zend Framework.

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

Фреймворк PHPUnit может показаться очень знакомым тем разработчикам, которые пришли из Java. Разработчики PHPUnit черпали вдохновение из JUnit — тестовом фреймворке для платформы Java, поэтому вы будете чувствовать себя как дома при использовании PHPUnit если вам уже приходилось сталкиваться с JUnit или одним из его клонов.

Конечно, никто не запрещает вам использовать системы бок о бок (даже в одном и том же приложении). В конце концов, большинство проектов так и будет использовать.

Использование PHPUnit


app/
    config/
    controllers/
        ExampleController.php
    models/
    views/
lib/
    Zend/
public/
tests/
    controllers/
        AllTests.php
        ExampleControllerTest.php
    lib/
    AllTests.php
    bootstrap.php


Тестовый набор нуждается в некоторой информации об окружении, и обычно эта информация находится в файле bootstrap.php. Самым большим отличием этого файла от одного из из используемых в вашем приложении является то, что Фронт-контроллер не выполняет диспетчеризацию объекта запроса:

tests/bootstrap.php
<?php
/* Start output buffering */
ob_start();

/* Report all errors directly to the screen for simple diagnostics in the dev environment */
error_reporting( E_ALL | E_STRICT );
ini_set('display_startup_errors', 1);
ini_set('display_errors', 1);
date_default_timezone_set('Europe/London');

/* Determine the root and library directories of the application */
$appRoot = dirname(__FILE__) . '/..';
$libDir = "$appRoot/lib";
$path = array($libDir, get_include_path());
set_include_path(implode(PATH_SEPARATOR, $path));

define('APPLICATION_PATH', $appRoot . '/app');
define('APPLICATION_ENVIRONMENT', 'dev');

require_once "Zend/Loader.php";
Zend_Loader::registerAutoload();

$front = Zend_Controller_Front::getInstance();
$front->throwExceptions(true);
$front->setParam('noViewRenderer', true);
$front->setParam('env', APPLICATION_ENVIRONMENT);
$front->setRequest(new Zend_Controller_Request_Http());
$front->returnResponse(true);

$router = $front->getRouter();
include APPLICATION_PATH . '/config/routes.php';
$router->addRoutes($routes);
$router->setParams($front->getParams());

$dispatcher = $front->getDispatcher();
$dispatcher->setParams($front->getParams());
$dispatcher->setResponse($front->getResponse());
$router->route($front->getRequest());


Обратите внимание! Отключение помощника ViewRenderer является не обязательным. Однако, вам должно быть известно, что использование класса Zend_Controller_Action_Helper_ViewRenderer может привести к снижению производительности. Подробнее об этом можно прочесть здесь.

Класс PHPUnit_Framework_TestSuite фреймворка PHPUnit позволяет вам организовать тесты в иерархические наборы тестов:

tests/AllTests.php
<?php
require_once dirname(__FILE__) . '/bootstrap.php';
require_once dirname(__FILE__) . '/controllers/AllTests.php';

class AllTests
{
    public static function main()
    {
        $parameters = array();
        PHPUnit_TextUI_TestRunner::run(self::suite(), $parameters);
    }

    public static function suite()
    {
        $suite = new PHPUnit_Framework_TestSuite('My Application');
        $suite->addTest(ControllersAllTests::suite());
        return $suite;
    }
}
AllTests::main();


tests/controllers/AllTests.php
<?php
require_once dirname(__FILE__) . '/ExampleControllerTest.php';

class ControllersAllTests
{
    public static function main()
    {
        PHPUnit_TextUI_TestRunner::run(self::suite());
    }
    public static function suite()
    {
        $suite = new PHPUnit_Framework_TestSuite('My Application - Controllers');
        $suite->addTestSuite('ExampleControllerTestCase');
        return $suite;
    }
}


Написание модульных тестов


Из-за довольно странных причин эта часть не описана в документации. Вот что вам нужно сделать до написания теста:

1. Подключить контроллер, который вы собираетесь тестировать.
2. Расширить контроллер действий (унаследовавшись от него).
3. Сбросить состояние экземпляра фронт-контроллера.
4. Указать путь к тестируемому контроллеру действий.
5. Установить объекты Запроса и Ответа.
6. Создать экземпляр тестируемого объекта.

Пример:
tests/controllers/ExampleControllerTest.php
<?php
require_once APPLICATION_PATH . '/controllers/ExampleController.php';

class ExampleControllerTest extends ExampleController
{
    public function __construct($url = null)
    {
        $front = Zend_Controller_Front::getInstance();
        $front->resetInstance();
        $front->setControllerDirectory(APPLICATION_PATH . '/controllers');
        $front->setRequest(new Zend_Controller_Request_Http($url));
        $front->setResponse(new Zend_Controller_Response_Http());
        parent::__construct($front->getRequest(), $front->getResponse());
    }
}


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

А теперь пришло время создать наш первый тестовый набор. Тестовый набор это класс, наследуемый от PHPUnit_Framework_TestCase, содержащий тестовые методы, определяемые по префиксу «test» в названии метода.

require_once APPLICATION_PATH . '/controllers/ExampleController.php';

class ExampleControllerTest extends ExampleController
{
    ...
}

class ExampleControllerTestCase extends PHPUnit_Framework_TestCase
{
    public function testDefaultAction()
    {
        $controller = new ExampleControllerTest();
        $isDispatched = $controller->indexAction();

        $this->assertTrue($isDispatched);
    }

    public function testFirstAction()
    {
        $url = 'http://localhost/example/first';
        $controller = new ExampleControllerTest($url);
        $controller->firstAction();
        $errorMsg = $controller->getRequest()->getParam('error_message', null);

        $this->assertEquals(null, $errorMsg);
    }

    public function testGetParameterName()
    {
        $url = 'http://localhost/example/first/fed';
        $controller = new ExampleControllerTest($url);
        $name = $controller->getRequest()->getParam('name', null);

        $this->assertEquals('fed', $name);
    }

    public function testGetNameMethod()
    {
        $url = 'http://localhost/example/first/fed';
        $controller = new ExampleControllerTest($url);
        $name = $controller->getName();
        $this->assertEquals('fed', $name);
    }
}

Запуск тестов



federico@tests$ phpunit AllTests
PHPUnit 3.3.8 by Sebastian Bergmann.
.....
Time: 0 seconds
OK (4 tests, 4 assertions)


Если тестирование завершится неудачно, то вы увидите подробную информацию о проваленном тесте. По желанию, вы можете подключить Phing в Hudson и автоматизировать выполнение этой задачи. Если есть вопросы — обращайтесь.]]>
Wed, 29 Apr 2009 10:33:29 +0300 igorok юнит-тесты тестирование программирование php zend framework фреймворк
<![CDATA[Как работает rand?]]> http://www.php5.com.ua/blog/php-programming/60.html http://www.php5.com.ua/blog/php-programming/60.html /** * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann * (http://qbnz.com/highlighter/ and http://geshi.org/) */ .php.php {color: #000066; border: 1px solid #d0d0d0; background-color: #f0f0f0;} .php.php a:link {color: #000060;} .php.php a:hover {background-color: #f0f000;} .php.php .imp {font-weight: bold; color: red;} .php.php .kw1 {color: #b1b100;} .php.php .kw2 {color: #000000; font-weight: bold;} .php.php .kw3 {color: #990000;} .php.php .co1 {color: #666666; font-style: italic;} .php.php .co2 {color: #666666; font-style: italic;} .php.php .co3 {color: #0000cc; font-style: italic;} .php.php .co4 {color: #0000ff; font-style: italic;} .php.php .coMULTI {color: #666666; font-style: italic;} .php.php .es_h {color: #000099; font-weight: bold;} .php.php .es_h {color: #000099; font-weight: bold;} .php.php .br0 {color: #009900;} .php.php .sy0 {color: #339933;} .php.php .st0 {color: #0000ff;} .php.php .st_h {color: #0000ff;} .php.php .nu0 {color: #cc66cc;} .php.php .nu8 {color: #208080;} .php.php .nu12 {color: #208080;} .php.php .nu19 {color:#800080;} .php.php .me1 {color: #004000;} .php.php .me2 {color: #004000;} .php.php .re0 {color: #000088;} .php.php span.xtra { display:block; } Столкнулся с задачкой генерации логинов. Недолго думая была написана такая функция:


private function _get_login() {
       
        $login = "";                           
        for( $i=0; $i<=9; $i++ ) {

                $login .= chr( rand( 97, 122 ) );
        }
        return $login;
}
 


Которая по моему скромному мнению должна была генерировать уникальные логины, которые живому человеку придумать тяжело. Упор ставился именно на уникальность.
Если посчитать, количество таких логинов примерно 141167095653376. Логины генерировались и вставлялись в БД. Каково же было моё удивление когда после генерации примерно 1000 логинов посыпались ошибки добавления в базу при срабатывании констрейнтов не уникальности данных. Причем ошибки не единичные, а десятки логинов подряд вылетали. Начал исследовать — выяснилось эта функция действительно генерирует повторяющиеся логины=\. Как такое может быть, что бы последовательности из 10 случайных чисел совпадали так часто? Ответа на этот вопрос так и не нашел. Перешел на использование функции mt_rand(), которая работает в 4 раза быстрее обычной rand(), имеет какие-то известные гарантированные характеристики работы(в отличии от rand()) и добавил элементарную проверку.
Получилось так:


private function _get_login() {
       
       
        $done = false;
        while( !$done ) {
               
                $login = "";                           
                for( $i=0; $i<=9; $i++ ) {

                        $login .= chr( mt_rand( 97, 122 ) );
                }
                $sql = "SELECT count(*) FROM users WHERE login='$login'";
                if($this->db->fetchRow( $sql ) == 0)
                        $done = true;
        }
       
        return $login;
}
 


Может у вас будут идеи по усовершенствованию алгоритма генерации логинов что бы они удовлетворяли следующим условиям:
-более-менее удобочитаемы, а не что-то невнятное вида qlgkakxwci
-более-менее уникальные — что-то типа qlgkakxwci =)

Спасибо за внимание.]]>
Mon, 06 Apr 2009 00:09:17 +0300 qubit rand mt_rand php говнокод
<![CDATA[Пишем веб-сервис с использованием протокола SOAP]]> http://www.php5.com.ua/blog/php-programming/53.html http://www.php5.com.ua/blog/php-programming/53.html /** * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann * (http://qbnz.com/highlighter/ and http://geshi.org/) */ .php.php {color: #000066; border: 1px solid #d0d0d0; background-color: #f0f0f0;} .php.php a:link {color: #000060;} .php.php a:hover {background-color: #f0f000;} .php.php .imp {font-weight: bold; color: red;} .php.php .kw1 {color: #b1b100;} .php.php .kw2 {color: #000000; font-weight: bold;} .php.php .kw3 {color: #990000;} .php.php .co1 {color: #666666; font-style: italic;} .php.php .co2 {color: #666666; font-style: italic;} .php.php .co3 {color: #0000cc; font-style: italic;} .php.php .co4 {color: #0000ff; font-style: italic;} .php.php .coMULTI {color: #666666; font-style: italic;} .php.php .es_h {color: #000099; font-weight: bold;} .php.php .es_h {color: #000099; font-weight: bold;} .php.php .br0 {color: #009900;} .php.php .sy0 {color: #339933;} .php.php .st0 {color: #0000ff;} .php.php .st_h {color: #0000ff;} .php.php .nu0 {color: #cc66cc;} .php.php .nu8 {color: #208080;} .php.php .nu12 {color: #208080;} .php.php .nu19 {color:#800080;} .php.php .me1 {color: #004000;} .php.php .me2 {color: #004000;} .php.php .re0 {color: #000088;} .php.php span.xtra { display:block; } В главных ролях:
— фреймворк CodeIgniter
— протокол SOAP
— методы getCategories() и getVideos($params = array()) — придуманы для примера
— сайт www.videobox.su используется просто, как заглушка, просто не хотел писать yourdomain.com

Для чего нам нужен SOAP


У нас есть ресурс с определенными данными, например, это будет видео ресурс. Мы хотим дать возможность другим ресурсам тянуть данные с нашего сайта. Было бы хорошо дать возможность сторонним программистам вызывать наши методы. Именно с вызовом удаленных процедур нам поможет SOAP.

Структура сей системы:

— Клиент
— Сервер

Пишем сервер


Мы хотим отдать на доступ два метода getCategories(), который будет возвращать список всех категорий нашего сайта и getVideos($params = array()) — он будет отдавать список видео с информацией в зависимости от входящих параметров $params.

Для начала нам необходимо создать WSDL документ, который опишет два наших метода (имеа методов, входящие данные и возвращаемые данные), по сути это файл в обычном XML формате.
Назовем наш файл webservice.wsdl и положим его по адресу http://videobox.su/webservice/webservice.wsdl
<?xml version ='1.0' encoding ='UTF-8' ?>
<definitions name='webservice'
targetNamespace='uri:webservice'
xmlns:tns='uro:webservice'
xmlns:soap='http://schemas.xmlsoap.org/wsdl/soap/'
xmlns:xsd='http://www.w3.org/2001/XMLSchema'
xmlns:soapenc='http://schemas.xmlsoap.org/soap/encoding/'
xmlns:wsdl='http://schemas.xmlsoap.org/wsdl/'
xmlns='http://schemas.xmlsoap.org/wsdl/'>

<types>
<!-- описываем тип данных ArrayOfParams, т.к. просто входящим параметром данные типа Array SOAP принимать не умеет -->
        <schema targetNamespace="http://example.com/stockquote/schema" xmlns="http://www.w3.org/2000/10/XMLSchema">
                <complexType name="ArrayOfParams">
                        <complexContent>
                                <restriction base="soapenc:Array">
                                        <attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:string[]"/>
                                </restriction>
                        </complexContent>
                </complexType>
        </schema>
</types>
<message name='getVideosRequest'>
        <part name='params' type='xsd:ArrayOfParams'/>
</message>
<message name='getVideosResponse'>
        <part name='Result' type='xsd:Array'/>
</message>
<!-- т.к. входящих параметров для метода getCategories() нет, мы не описываем Request -->
<message name='getCategoriesResponse'>
        <part name='Result' type='xsd:Array'/>
</message>
<portType name='webservicePortType'>
        <operation name='getVideos'>
                <input message='tns:getVideosRequest'/>
                <output message='tns:getVideosResponse'/>
        </operation>
        <operation name='getCategories'>
                <input message='tns:getCategoriesRequest'/>
                <output message='tns:getCategoriesResponse'/>
        </operation>
</portType>
<binding name='webserviceBinding' type='tns:webservicePortType'>
  <soap:binding style='rpc' transport='http://schemas.xmlsoap.org/soap/http'/>
  <operation name='getVideos'>
    <soap:operation soapAction='urn:webservice-video#getVideos'/>
    <input>
      <soap:body use='encoded' namespace='urn:webservice-video' encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
    </input>
    <output>
      <soap:body use='encoded' namespace='urn:webservice-video' encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
    </output>
  </operation>
  <operation name='getCategories'>
    <soap:operation soapAction='urn:webservice-video#getCategories'/>
    <input>
      <soap:body use='encoded' namespace='urn:webservice-video' encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
    </input>
    <output>
      <soap:body use='encoded' namespace='urn:webservice-video' encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
    </output>
  </operation>
</binding>
<service name='webserviceService'>
        <port name='webservicePort' binding='webserviceBinding'>
<!-- URL к нашему серверу -->
                <soap:address location='http://videobox.su/webservice/'/>
        </port>
</service>
</definitions>


Создадим контроллер, который и будет являться нашим сервером.
<?
class Webservice extends Controller{
        function __construct(){
                parent::Controller();
                $this->load->model("video");
                $this->load->model("category");

        }
        function index(){
                function getVideos($params) {
                        $CI = &get_instance ();
                        $videos = array();
//проверка входящих данных
                        if(!is_array($params) || sizeof($params) == 0) {
                                throw new SoapFault("Server:", '$params' . " has wrong format. Can be Array();");
                        }
                        else {
                                return $CI->video->getVideo($params); // выборка данных по видео, здесь можно описать свой код, для краткости сделан вызов из модели
                        }

                }
                function getCategories() {
                        return $CI->category->getAll();  // выборка данных по категориям, здесь можно описать свой код, для краткости сделан вызов из модели
                }

                ini_set("soap.wsdl_cache_enabled", "0"); // отключение кеширования wsdl файла
                $server = new SoapServer("http://videobox.su/webservice/webservice.wsdl?" . rand()); // случайное число добавляем для дебага, т.к. wsdl файл сразуже кешируется и не всегда есть доступ к php.ini или к функции ini_set для отключения кеширования на кремя дебага
                $server->addFunction("getVideos");
                $server->addFunction("getCategories");
                $server->handle();
        }

?>

Наш сервер готов и доступен по адресу http://videobox.su/webservice/.

Пишем клиент


Клиент это та, часть, которая создается сторонними разработчиками с использованием методов, которые мы отдали для использования.

Опять же, создаем контроллер Webserviceclient (если клиент использует CodeIgniter) или не создаем, а а просто используем код, который описан в методе контроллера index(). В любом случае он будет доступен там, где вы его создали.

<?
class Webserviceclient extends Controller{
  function __construct(){
      parent::Controller();
  }
 
        function index(){
                try {
                        $client = new SoapClient("http://videobox.su/webservice/webservice.wsdl?" . rand(),
                                                                                array(
                                                                                        "trace"      => 1,
                                                                                        "exceptions" => 0
                                                                                )
                                                                        );//второй параметр необходим для отладки, является не обязательным
                $params = array(
                        "vid" => 64, //выбираем видео с ID = 64
                );
                print "<pre>";
                print_r($client->getVideos($params)); // вызов метода сервера на выборку данных по видео
                //print "Request :\n".htmlspecialchars($client->__getLastRequest()) ."\n
"; // показать запрос к серверу (работает при включенном дебаге), кому интересно посмотреть на XML - раскомментировать
                //print "
Answer:\n".htmlspecialchars($client->__getLastResponse())."\n
"; // показать ответ сервера (работает при включенном дебаге), кому интересно посмотреть на XML - раскомментировать
                print_r($client->getCategories()); // вызов метода сервера на выборку доступных категорий
                //print "
Request :\n".htmlspecialchars($client->__getLastRequest()) ."\n
";
                //print "
Answer:\n".htmlspecialchars($client->__getLastResponse())."\n
";
                print "
</pre>";
                }
                catch (Exception $e){
                        print $e;
                        echo 'Error Caught';
                }
        }
 
}
?>


В результате мы получим вывод двух массивов данных или в чем придумаете выдачу данных в своей реализации.

Статья была написана в качестве примера, т.к. в интернете не было найдено ничего толкового, а именно были описаны абстрактные примеры, которые трудно соединить в систему, так же сложно было найти, как передать массив в качестве параметра:)]]>
Mon, 23 Mar 2009 11:58:40 +0200 igorok SOAP веб-сервис клиен сервер WSDL
<![CDATA[Удаление коротких слов]]> http://www.php5.com.ua/blog/php-programming/36.html http://www.php5.com.ua/blog/php-programming/36.html /** * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann * (http://qbnz.com/highlighter/ and http://geshi.org/) */ .php.php {color: #000066; border: 1px solid #d0d0d0; background-color: #f0f0f0;} .php.php a:link {color: #000060;} .php.php a:hover {background-color: #f0f000;} .php.php .imp {font-weight: bold; color: red;} .php.php .kw1 {color: #b1b100;} .php.php .kw2 {color: #000000; font-weight: bold;} .php.php .kw3 {color: #990000;} .php.php .co1 {color: #666666; font-style: italic;} .php.php .co2 {color: #666666; font-style: italic;} .php.php .co3 {color: #0000cc; font-style: italic;} .php.php .co4 {color: #0000ff; font-style: italic;} .php.php .coMULTI {color: #666666; font-style: italic;} .php.php .es_h {color: #000099; font-weight: bold;} .php.php .es_h {color: #000099; font-weight: bold;} .php.php .br0 {color: #009900;} .php.php .sy0 {color: #339933;} .php.php .st0 {color: #0000ff;} .php.php .st_h {color: #0000ff;} .php.php .nu0 {color: #cc66cc;} .php.php .nu8 {color: #208080;} .php.php .nu12 {color: #208080;} .php.php .nu19 {color:#800080;} .php.php .me1 {color: #004000;} .php.php .me2 {color: #004000;} .php.php .re0 {color: #000088;} .php.php span.xtra { display:block; } В повседневной жизни иногда пирходится удалять короткие слова из текстов
function deleteShortWords($text, $word_lenght = 3) {
                return preg_replace('/( |^)[a-zа-я]{1,' . $word_lenght . '}( |$)/isu', ' ', $text);
        }

Вторым параметром передается количество символов в слове.]]>
Fri, 13 Feb 2009 11:49:57 +0200 igorok cut word short
<![CDATA[Преобразовать слово в URL]]> http://www.php5.com.ua/blog/php-programming/35.html http://www.php5.com.ua/blog/php-programming/35.html /** * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann * (http://qbnz.com/highlighter/ and http://geshi.org/) */ .php.php {color: #000066; border: 1px solid #d0d0d0; background-color: #f0f0f0;} .php.php a:link {color: #000060;} .php.php a:hover {background-color: #f0f000;} .php.php .imp {font-weight: bold; color: red;} .php.php .kw1 {color: #b1b100;} .php.php .kw2 {color: #000000; font-weight: bold;} .php.php .kw3 {color: #990000;} .php.php .co1 {color: #666666; font-style: italic;} .php.php .co2 {color: #666666; font-style: italic;} .php.php .co3 {color: #0000cc; font-style: italic;} .php.php .co4 {color: #0000ff; font-style: italic;} .php.php .coMULTI {color: #666666; font-style: italic;} .php.php .es_h {color: #000099; font-weight: bold;} .php.php .es_h {color: #000099; font-weight: bold;} .php.php .br0 {color: #009900;} .php.php .sy0 {color: #339933;} .php.php .st0 {color: #0000ff;} .php.php .st_h {color: #0000ff;} .php.php .nu0 {color: #cc66cc;} .php.php .nu8 {color: #208080;} .php.php .nu12 {color: #208080;} .php.php .nu19 {color:#800080;} .php.php .me1 {color: #004000;} .php.php .me2 {color: #004000;} .php.php .re0 {color: #000088;} .php.php span.xtra { display:block; } Я уже писал о маленькой полезности для транслитерации слов.
Сегодня у нас в гостях фунция, которая умеет делать из русских слов ЧПУ линки.

function word2URL($text) {
                $text = translit($text); // здесь запользовали функцию транслитерации
                $good_liters= '#[^-a-zA-Z0-9 _]#';
                $text = strtolower(trim(preg_replace($good_liters, '', $text)));
                return preg_replace('#[-_ ]+#', '-', $text);
        }
]]>
Fri, 13 Feb 2009 11:46:59 +0200 igorok ЧПУ ссылка
<![CDATA[Установка ORM Doctrine на Codeigniter (перевод на русский)]]> http://www.php5.com.ua/blog/php-programming/29.html http://www.php5.com.ua/blog/php-programming/29.html /** * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann * (http://qbnz.com/highlighter/ and http://geshi.org/) */ .php.php {color: #000066; border: 1px solid #d0d0d0; background-color: #f0f0f0;} .php.php a:link {color: #000060;} .php.php a:hover {background-color: #f0f000;} .php.php .imp {font-weight: bold; color: red;} .php.php .kw1 {color: #b1b100;} .php.php .kw2 {color: #000000; font-weight: bold;} .php.php .kw3 {color: #990000;} .php.php .co1 {color: #666666; font-style: italic;} .php.php .co2 {color: #666666; font-style: italic;} .php.php .co3 {color: #0000cc; font-style: italic;} .php.php .co4 {color: #0000ff; font-style: italic;} .php.php .coMULTI {color: #666666; font-style: italic;} .php.php .es_h {color: #000099; font-weight: bold;} .php.php .es_h {color: #000099; font-weight: bold;} .php.php .br0 {color: #009900;} .php.php .sy0 {color: #339933;} .php.php .st0 {color: #0000ff;} .php.php .st_h {color: #0000ff;} .php.php .nu0 {color: #cc66cc;} .php.php .nu8 {color: #208080;} .php.php .nu12 {color: #208080;} .php.php .nu19 {color:#800080;} .php.php .me1 {color: #004000;} .php.php .me2 {color: #004000;} .php.php .re0 {color: #000088;} .php.php span.xtra { display:block; } Предисловие:
На хабре была описана Правильная интеграция Doctrine в CodeIgniter. Она то, казалось бы, и правильная, но последняя строка мне не очень понравилась: UPD2: в config/autoload.php обязательно надо выключить «database» из списка загружаемых библиотек. Получается, что с БД, при подключенном Doctrine мы работать не сможем.

Скачать Doctrine


В первую очередь, необходимо скачать последнюю версию Doctrine. И положить в папку system/database.
Для линуксоидов:
$ cd system/database
$ svn co http://svn.phpdoctrine.org/branches/0.10/lib doctrine
$ cd ..

// If you use svn in your project you can set Doctrine
// as an external so you receive bug fixes automatically from svn
$ svn propedit svn:externals database

// In your favorite editor add the following line
// doctrine http://svn.phpdoctrine.org/branches/0.10/lib

Установка Doctrine


Конфигурировать доктрин мы будем в файле system/application/config/database.php. Для этого нам необходимо открыть его в любимом редакторе. А линуксоидам сделать следующее:
$ vi application/config/database.php


Далее находим строку:
$db['default']['cachedir'] = "";

И ниже дописываем:

// Create dsn from the info above
$db['default']['dsn'] = $db['default']['dbdriver'] .
                        '://' . $db['default']['username'] .
                        ':' . $db['default']['password'].
                        '@' . $db['default']['hostname'] .
                        '/' . $db['default']['database'];

// Require Doctrine.php
require_once(realpath(dirname(__FILE__) . '/../..') . DIRECTORY_SEPARATOR . 'database/doctrine/Doctrine.php');

// Set the autoloader
spl_autoload_register(array('Doctrine', 'autoload'));

// Load the Doctrine connection
Doctrine_Manager::connection($db['default']['dsn'], $db['default']['database']);

// Load the models for the autoloader
Doctrine::loadModels(realpath(dirname(__FILE__) . '/..') . DIRECTORY_SEPARATOR . 'models');


Далее подключаем файл application/config/database.php в свой фронт контроллер это файл index.php в корне вашего проекта, его нужно открыть любимым редактором.
Линуксоидам сделать так:
$ cd ..
$ vi index.php

Меняем две последних строчки кода на:
require_once APPPATH.'config/database.php';
require_once BASEPATH.'codeigniter/CodeIgniter'.EXT;

Установка Comand Line интерфейса


Создайте файл system/application/doctrine (без расширения). Линуксоидам:
$ vi system/application/doctrine

Поместите туда следующий код:
<?php
require_once('config/database.php');

// Configure Doctrine Cli
// Normally these are arguments to the cli tasks but if they are set here the arguments will be auto-filled
$config = array('data_fixtures_path'  =>  dirname(__FILE__) . DIRECTORY_SEPARATOR . '/fixtures',
                'models_path'         =>  dirname(__FILE__) . DIRECTORY_SEPARATOR . '/models',
                'migrations_path'     =>  dirname(__FILE__) . DIRECTORY_SEPARATOR . '/migrations',
                'sql_path'            =>  dirname(__FILE__) . DIRECTORY_SEPARATOR . '/sql',
                'yaml_schema_path'    =>  dirname(__FILE__) . DIRECTORY_SEPARATOR . '/schema');

$cli = new Doctrine_Cli($config);
$cli->run($_SERVER['argv']);

Далее создаем папки для нужд и испражнений Doctrine.
system/application/fixtures
system/application/migrations
system/application/schema
system/application/sql

TODO линуксоидам:
// Create directory for your yaml data fixtures files
$ mkdir system/application/fixtures

// Create directory for your migration classes
$ mkdir system/application/migrations

// Create directory for your yaml schema files
$ mkdir system/application/schema

// Create directory to generate your sql to create the database in
$ mkdir system/application/sql


Наш Comand Line интерфейс готов. Дальше всеравно прийдется лезть в командную строку:) Для того что бы просмотреть все, что умеет Doctrine, необходимо запустить shell скрипт:
$ cd system/application
$ ./doctrine
Doctrine Command Line Interface

./doctrine build-all
./doctrine build-all-load
./doctrine build-all-reload
./doctrine compile
./doctrine create-db
./doctrine create-tables
./doctrine dql
./doctrine drop-db
./doctrine dump-data
./doctrine generate-migration
./doctrine generate-migrations-db
./doctrine generate-migrations-models
./doctrine generate-models-db
./doctrine generate-models-yaml
./doctrine generate-sql
./doctrine generate-yaml-db
./doctrine generate-yaml-models
./doctrine load-data
./doctrine load-dummy-data
./doctrine migrate
./doctrine rebuild-db
$

Для фанатов видоуса необходимо запустить скрипт через php
> php.exe doctrine

Использование Doctrine


Для начала работы создадим yaml схему.
---
User:
  columns:
    username:
      type: string(255)
    password:
      type: string(255)

И положим его в папку system/application/schema. Следующая команда сгенерит нам модели (php классы для работы с данными) из yaml файлов и положит их в system/application/models
$ ./doctrine generate-models-yaml
generate-models-yaml - Generated models successfully from YAML schema

Что бы посмотреть, что нам нагенерил Doctrine откроем файл system/application/models/generated/BaseUser.php
<?php

/**
* This class has been auto-generated by the Doctrine ORM Framework
*/

abstract class BaseUser extends Doctrine_Record
{
  public function setTableDefinition()
  {
    $this->setTableName('user');
    $this->hasColumn('username', 'string', 255, array (
));
    $this->hasColumn('password', 'string', 255, array (
));
  }
}

// Add custom methods to system/application/models/User.php

<?php

/**
* This class has been auto-generated by the Doctrine ORM Framework
*/

class User extends BaseUser
{
  public function setPassword($password)
  {
    $this->password = md5($password);
  }
}

/**
* This class has been auto-generated by the Doctrine ORM Framework
*/

class UserTable extends Doctrine_Table
{
  public function retrieveAll()
  {
    $query = new Doctrine_Query();
    $query->from('User u');
    $query->orderby('u.username ASC');

    return $query->execute();
  }
}

Создадим тестовые данные для загрузки в наше приложение. Для этого необходимо создать файл system/application/fixtures/users.yml. И в нем прописать данные:
---
User:
  jwage:
    username: jwage
    password: test

Командой build-all-reload мы пересоздадим нашу БД и модели
$ ./doctrine build-all-reload
build-all-reload - Are you sure you wish to drop your databases? (y/n)
y
build-all-reload - Successfully dropped database named: "jwage_codeigniter"
build-all-reload - Generated models successfully from YAML schema
build-all-reload - Successfully created database named: "jwage_codeigniter"
build-all-reload - Created tables successfully
build-all-reload - Data was successfully loaded

Для того. что бы убедиться, что все сделано правильно откройте/создайте system/application/views/welcome_message.php и добавьте следующий код:
$user = new User();
$user->username = 'zYne-';
$user->setPassword('password');
$user->save();

$userTable = Doctrine::getTable('User');
$user = $userTable->findOneByUsername('zYne-');

echo $user->username; // prints 'zYne-'

$users = $userTable->retrieveAll();

echo $users->count(); // echo '2''
foreach ($users as $user)
{
  echo $user->username;
}
]]>
Mon, 02 Feb 2009 11:27:36 +0200 igorok doctine ORM CodeIgniter framework
<![CDATA[Функция для транслитерации слов]]> http://www.php5.com.ua/blog/php-programming/17.html http://www.php5.com.ua/blog/php-programming/17.html /** * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann * (http://qbnz.com/highlighter/ and http://geshi.org/) */ .php.php {color: #000066; border: 1px solid #d0d0d0; background-color: #f0f0f0;} .php.php a:link {color: #000060;} .php.php a:hover {background-color: #f0f000;} .php.php .imp {font-weight: bold; color: red;} .php.php .kw1 {color: #b1b100;} .php.php .kw2 {color: #000000; font-weight: bold;} .php.php .kw3 {color: #990000;} .php.php .co1 {color: #666666; font-style: italic;} .php.php .co2 {color: #666666; font-style: italic;} .php.php .co3 {color: #0000cc; font-style: italic;} .php.php .co4 {color: #0000ff; font-style: italic;} .php.php .coMULTI {color: #666666; font-style: italic;} .php.php .es_h {color: #000099; font-weight: bold;} .php.php .es_h {color: #000099; font-weight: bold;} .php.php .br0 {color: #009900;} .php.php .sy0 {color: #339933;} .php.php .st0 {color: #0000ff;} .php.php .st_h {color: #0000ff;} .php.php .nu0 {color: #cc66cc;} .php.php .nu8 {color: #208080;} .php.php .nu12 {color: #208080;} .php.php .nu19 {color:#800080;} .php.php .me1 {color: #004000;} .php.php .me2 {color: #004000;} .php.php .re0 {color: #000088;} .php.php span.xtra { display:block; } Необходимо было написать функцию транслитерации кирилицы в латиницу. Пошарился по интернету, нашел много неоптимальных говнорешений. Написал свое мегарешение:)

При транслитерации использовался стандарт ISO 9 — 1995 (Transliteration of Slavic Cyrillic characters into Latin characters).


        /**
         * transliterate text
         *
         * @param string $text
         * @return string
         */

       
        function translit($text) {
                $trans = array(
                                        "а" => "a",
                                        "б" => "b",
                                        "в" => "v",
                                        "г" => "g",
                                        "д" => "d",
                                        "е" => "e",
                                        "ё" => "e",
                                        "ж" => "zh",
                                        "з" => "z",
                                        "и" => "i",
                                        "й" => "y",
                                        "к" => "k",
                                        "л" => "l",
                                        "м" => "m",
                                        "н" => "n",
                                        "о" => "o",
                                        "п" => "p",
                                        "р" => "r",
                                        "с" => "s",
                                        "т" => "t",
                                        "у" => "u",
                                        "ф" => "f",
                                        "х" => "kh",
                                        "ц" => "ts",
                                        "ч" => "ch",
                                        "ш" => "sh",
                                        "щ" => "shch",
                                        "ы" => "y",
                                        "э" => "e",
                                        "ю" => "yu",
                                        "я" => "ya",
                                        "А" => "A",
                                        "Б" => "B",
                                        "В" => "V",
                                        "Г" => "G",
                                        "Д" => "D",
                                        "Е" => "E",
                                        "Ё" => "E",
                                        "Ж" => "Zh",
                                        "З" => "Z",
                                        "И" => "I",
                                        "Й" => "Y",
                                        "К" => "K",
                                        "Л" => "L",
                                        "М" => "M",
                                        "Н" => "N",
                                        "О" => "O",
                                        "П" => "P",
                                        "Р" => "R",
                                        "С" => "S",
                                        "Т" => "T",
                                        "У" => "U",
                                        "Ф" => "F",
                                        "Х" => "Kh",
                                        "Ц" => "Ts",
                                        "Ч" => "Ch",
                                        "Ш" => "Sh",
                                        "Щ" => "Shch",
                                        "Ы" => "Y",
                                        "Э" => "E",
                                        "Ю" => "Yu",
                                        "Я" => "Ya",
                                        "ь" => "",
                                        "Ь" => "",
                                        "ъ" => "",
                                        "Ъ" => ""
                                );
                if(preg_match("/[а-яА-Я]/", $text)) {
                        return strtr($text, $trans);                   
                }
                else {
                        return $text;
                }
                               
        }
]]>
Mon, 29 Dec 2008 12:21:40 +0200 igorok транслитерация кирилица латиница
<![CDATA[HTML парсер]]> http://www.php5.com.ua/blog/php-programming/14.html http://www.php5.com.ua/blog/php-programming/14.html
На днях нужно было распарсить один сайт, с регулярными выражениями возиться не очень хотелось, скажем, возиться вообще ни с чем не хотелось:)) Хотелось инструмент, который будет простым в использовании и качественно выполнять поставленную задачу.

Нашел набор функций, который называется Simple HTML DOM. Который оказался очень простым в использовании, парсит тоже хорошо, есдинственный минус, который я нашел — при выдирании линков из тега «a», к линку, через пробел, иногда дописывает какой-то четырехсимвольный бред.

Документация:
использование
API
FAQ

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

Парсим google.com:
Пример использования основных селекторов
Callback функции
Чтение соурса и очистка текста от HTML
Изменение прочитанного контента
Поиск элемента содержащего заданный текст

Парсим Digg
Парсим imdb
Парсим slashdot

Скачать simplehtmldom.zip]]>
Mon, 22 Dec 2008 22:29:46 +0200 igorok парсер HTML