Что нового в PHP 5.3?
PHP 6 не за горами, но разработчики не могут терпеть несправедливости php 5.2, бэкпортировали возможности
шестерки в пятую ветку. Релиз которой состаялся в конце июня!
Насколько я знаю, портеры FreeBSD не сделали порт, поэтому обновляться либо вручную, либо ждать официально поддерживаемого порта.
PHP становится более объектно ориентированным языком - добавлена поддержка неймспейсов, но
корни языка попрежнему дают о себе знать - это и путаница в параметрах haystack-needle и "программистские пробелы"
в названиях функций.
Namespaces - неймспейсы - пространства имён
В бетах php 5.3 разделителем имен был символ "::", потом разработчики хорошо подумали и ими был выбран
новый разделительный символ "\" бэкслеш, аля windows-path-separator. Теперь наш код будет смотреться удивительно
красиво - то ли мы экранируем символы, толи выделяем неймспейсы. мрак..
Вот пример кода. Одному мне кажется, что слеши смотрятся убого и нелепо
(да, теперь все основные фукции явно указываются с глобальным контекстом).
if (empty($this->_options['register-only'])) {
if (!\file_exists($dest_dir) || !is_dir($dest_dir)) {
if (!\mkdir($dest_dir, 0755, true)) {
throw new Installer\Exception("failed to mkdir $dest_dir");
}
Log::log(3, "+ mkdir $dest_dir");
}
Почему они выбрали этот разделитель?
\1\Тема\на\stackoverflow
\2\RFC-Стори\на\PHP\wiki
PHP всегда был особенным, не совсем логичным языком.
<?php
class User {
public function set( $attribute, $value ) { ... }
public function save() { ... }
}
$user = new User();
$user->set('fullname', 'Ben Balbo');
$user->save();
В этом примере объявлен обычный класс User. Однако, если вы используете в своей разработке сторонние
библиотеки (ака фреймворки), то можете встретися с неприятной вещью - конфликтом имен. Именно поэтому
в эпоху динозавров к именам классов-переменныъ приходилось добавлять префиксы. Возьмите тот же zend framework -
все объявления классов начинаются с префикса Zend_, что не очень удобно и читабельно.
Итак, на помощь нам приходят неймспейсы. Кто вообще не в теме, неймспейсы - это так называемые "области видимости" или
можно сказать "контексты выполнения". Ранее все скрипты выполнялись в глобальном неймспейсе-контексте, теперь вы можете
объявить свои, чтобы исключить конфликты.
Смотрите код
<?php
namespace MyCompany\Blog;
class User {
public function set( $attribute, $value ) {
$this->$attribute = $value;
}
public function save() {
echo '<p>Blog user ' . $this->fullname . ' saved</p>';
}
}
<?php
$user = new MyCompany\Blog\User();
$user->set('fullname', 'Ben Balbo');
$user->save();
Здесь вы явно указываете, что создаете экземпляр класса User именно из необходимого неймспейса.
Вероятнее всего, раньше бы этот класс назывался не иначе как MyCompany_Blog_User.
Сейчас, имеем имя MyCompany\Blog\User.
<?php
namespace MyCompany\CMS;
class User {
public function set( $attribute, $value ) {
$this->$attribute = $value;
}
public function save() {
echo '<p>CMS user ' . $this->fullname . ' saved</p>';
}
}
Усложним задачу - добавим еще один класс User, но в другом неймспейсе. Теперь мы можем манипулировать
разными "Юзерами", обращаясь к классу полным именем MyCompany\Blog\User и MyCompany\CMS\User.
The use Keyword
Для того чтобы не перегружать код программы, используются ключевое слово "use",
с помощью которого мы указываем интерпретатору, какой неймспейс мы хотим сейчас использовать.
<?php
use MyCompany\Blog;
$user = new Blog\User();
$post = new Blog\Post();
$post->setUser( $user );
$post->setTitle( $title );
$post->setBody( $body );
$post->save();
C помощью use можно также просто импортировать класс из другого неймспейса.
<?php
use MyCompany\Blog\User;
$user = new User();
Namespace Aliases
Если по каким-то причинам вы не можете использовать одновременно несколько разных классов (из-за конфликтов к примеру),
язык позволяет создать алиасы (синонимы) для обращения к ним.
<?php
use MyCompany\Blog\User as BlogUser;
use MyCompany\CMS\User as CMSUser;
$bloguser = new BlogUser();
$bloguser->set('fullname', 'John Doe');
$bloguser->save();
$cmsuser = new CMSUser();
$cmsuser->set('fullname', 'John Doe');
$cmsuser->save();
Констаны классов
Константы объявляются следующим образом.
Этот код создаст две константы в неймспейсе test.
namespace test;
define('test\HELLO', 'Hello world!');
define(__NAMESPACE__ . '\GOODBYE', 'Goodbye cruel world!');
Единственное, на константу нельзя сделать алиас.
<?php
namespace MyCompany;
class Blog {
const VERSION = '1.0.0';
}
<?php
echo '<p>Blog bersion ' . MyCompany\Blog\VERSION . '</p>';
use MyCompany\Blog;
echo '<p>Blog version ' . Blog\VERSION . '</p>';
use MyCompany\Blog\VERSION as Foo;
echo '<p>Blog version ' . Foo . '</p>';
This will result in the following output:
Blog version 1.0.0
Blog version 1.0.0
Blog version Foo
В php 5.3 добавлены новые константы:
__NAMESPACE__ - текущий неймспейс
__DIR__ - текущая директория (ранее определялась dirname(__FILE__))
Функции в неймспейсах
В объектно ориентированном мире нет места функциям - их заменили статичные методы.
В PHP мы можем создавать функции в неймспейсах и обращаться к ним соответственно через их
область имен.
Пример:
<?php
namespace bundle;
function foo() { echo '<p>This is the bundled foo</p>'; }
foo(); // This prints 'This is the bundled foo'
<?php
function foo() { echo '<p>This is the global foo</p>'; }
require( 'lib/bundle.class.php');
bundle\foo(); // This prints 'This is the bundled foo'
foo(); // This prints 'This is the global foo'
Явный вызов функции из глобального контекста
Если ваш класс переопределяет метод из глобального неймспейса, вызвать
его можно следующим образом
<?php
namespace bundle;
function foo() { echo '<p>This is the bundled foo</p>'; }
foo(); // This prints 'This is the bundled foo'
\foo(); // This prints 'This is the global foo'
Автолоад классов в неймспейсах
Теперь в __autoload будет передаваться полное имя класса.
__autoload( 'MyCompany\Blog\User' );
Загрузку скрипта можно осуществить следующим образом
function __autoload( $classname ) {
$classname = strtolower( $classname );
$classname = str_replace( '\', DIRECTORY_SEPARATOR, $classname );
require_once( dirname( __FILE__ ) . '/' . $classname . '.class.php' );
}
Результатом вызова __autoload будет подключение скрипта ./classes/mycompany/blog/user.class.php.
Подробнее о неймспейсах
Late Static Binding, LSB, позднее связывание
Кто-то говорит про паттерн ActiveRecord?
LSB дает возможность вызывать в родительском классе переопределенные в результате наследования методы.
<?php
class ParentClass {
static public function say( $str ) {
self::do_print( $str );
}
static public function do_print( $str ) {
echo "<p>Parent says $str</p>";
}
}
class ChildClass extends ParentClass {
static public function do_print( $str ) {
echo "<p>Child says $str</p>";
}
}
ChildClass::say( 'Hello' );
Вероятнее всего вы ожидаете результата "Child says Hello", однако теперь результатом выполнения будет "Parent says Hello".
Причина в том что self:: и __CLASS__ резолвятся в имя класса, в котором они используются. PHP 5.3 включает ключевое
слово static::, значение которого указывает на статичный класс, в контексте которого был вызван метод.
static public function say( $str ) {
static::do_print( $str );
}
С использованием static\ скрипт выведет "Child says Hello".
__callstatic
До настоящего времени, у PHP в наличии были востребованные "волшебные методы" __set, __get и __call.
PHP 5.3 вводит в оборот новый метод __callstatic , который работает точно также как и __call,
за исключением того что он оперирует со статичным контекстом.
<?php
class Factory {
static function GetDatabaseHandle() {
echo '<p>Returns a database handle</p>';
}
static function __callstatic( $methodname, $args ) {
echo '<p>Unknown static method <strong>' . $methodname . '</strong>' .
' called with parameters:</p>';
echo '<pre>' . print_r( $args, true ) . '</pre>';
}
}
Factory::GetDatabaseHandle();
Factory::CreateUser();
Factory::CreateBlogPost( 'Author', 'Post Title', 'Post Body' );
Теперь вы можете вызывать динамически статичные методы.
$classname = 'Factory';
$methodname = 'CreateUser';
$classname::$methodname();
$methodname = 'CreateBlogPost';
$author = 'Author';
$posttitle = 'Post Title';
$postbody = 'Post Body';
$classname::$methodname( $author, $posttitle, $postbody );
Вы можете динамически создавать объекты.
<?php
require_once( 'lib/autoload.php' );
$class = 'MyCompany\Blog\User';
$user = new $class();
$user->set('fullname', 'Ben Balbo');
$user->save();
Хотя это не приветствуется, потому как затрудняет отладку, читаемость кода.
MySQL Native Driver - mysqlnd
Нативный драйвер mysql. Улучшена производительность благодаря интеграции библиотеки mysql и движка zend.
Также значительно улучшена работа драйвера с памятью, так как она теперь выделяется не напрямую, а с помощью
механизмов zend.
Подробнее о mysqlnd
E_STRICT
Да, да - теперь E_ALL по-умолчанию включает этот режим.
Также добавлена константа E_DEPRICATED, ошибки с уровнем которой будут возникать в случае использования функций,
помеченных как "устаревшие". И такие наверняка будут, потому как например "устарели"
call_user_method();
ereg(); // (use preg_match() instead)
ereg_replace(); // (use preg_replace() instead)
Полный список устаревших конструкций
Статья - вольный перевод http://www.sitepoint.com/article/whats-new-php-5-3/
Замыкания - closures
Раньше php не позволял создавать простые анонимные функции (функции без имени), вместо этого в языке была предусмотрена функция create_function.
Основное назначение анонимусов - в фукциях обратного вызова (callbacks).
echo preg_replace_callback('~-([a-z])~', function ($match) {
return strtoupper($match[1]);
}, 'hello-world');
// outputs helloWorld
В php 5.3 все объявления анонимных функций автоматически создаются как экземпляры внутреннего класса Closure.
$greet = function($name)
{
printf("Hello %s\r\n", $name);
};
$greet('World');
Замыкания могут создаваться внутри других методов. Для использования переменных из родительского контекста, их нужно явно
указать в заголовке функции.
public function getTotal($tax)
{
$total = 0.00;
$callback =
function ($quantity, $product) use ($tax, &$total)
{
$pricePerItem = constant(__CLASS__ . "\PRICE_" .
strtoupper($product));
$total += ($pricePerItem * $quantity) * ($tax + 1.0);
};
array_walk($this->products, $callback);
return round($total, 2);
}
Страница мануала по замыканиям
Тернарный оператор (ternary)
Обычная версия его выполняет роль if-then-else и используется следующим образом
(expr1) ? (expr2) : (expr3) // if (expr1) =expr2 else =expr3
С появлением PHP 5.3, возможно отбросить среднюю часть оператора (та что true) и сразу перейти к ложному условию.
Первая часть в таком случае равна самому условию.
expr1 ?: expr3 // if (expr1) =expr1 else =expr3
Страница мануала по тернарному оператору
Дополнительная информация по миграции с PHP 5.2 на 5.3
http://ru2.php.net/migration53