Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Epic PHP #5

Roma
March 13, 2014

Epic PHP #5

Слайды к пятому занятию курса Epic PHP (http://epixx.ru/epic-php/).
Темы: основы ООП, дизайн и паттерны, composer,

Roma

March 13, 2014
Tweet

More Decks by Roma

Other Decks in Programming

Transcript

  1. Epic PHP #5
    Рома Лапин, Evercode Lab

    View Slide

  2. Основы ООП

    View Slide

  3. Объекты?
    Стратегию ООП лучше всего описать как
    смещение приоритетов в процессе
    программирования от функциональности
    приложения к структурам данных. Это позволяет
    программисту моделировать в создаваемых
    приложениях реальные объекты и ситуации.

    View Slide

  4. ООП
    • Инкапсуляция

    • Полиморфизм

    • Наследование

    View Slide

  5. ООП

    View Slide

  6. Class
    class ComplicatedClass

    {

    !
    public $someVar = 'a default value';

    !
    public function displayVar() {

    echo $this->someVar;

    }

    }

    View Slide

  7. Class
    • Может содержать свои константы,
    переменные (свойства) и функции
    (методы)

    • Название класса не может быть
    зарезервированным словом PHP

    • Название может начинаться с буквы или
    символа подчеркивания и состоять из
    букв, цифр и _.

    View Slide

  8. $this
    Псевдопеременная, доступная, когда метод
    вызывается в контексте объекта. Является ссылкой
    на вызывающий объект.

    View Slide

  9. $this

    View Slide

  10. new
    $instance = new ComplicatedClass();

    !
    $className = 'Foo';

    $instance = new $className(); // Foo()

    View Slide

  11. new
    • Создает экземпляр класса

    • В контексте класса можно создать
    объект, используя new self или new
    parent

    View Slide

  12. Class vs Object?

    View Slide

  13. Class vs Object?

    View Slide

  14. Свойства
    // invalid property declarations:

    public $var1 = 'hello ' . 'world';

    public $var3 = 1+2;

    public $var4 = self::myStaticMethod();

    public $var5 = $myVar;

    !
    // valid property declarations:

    public $var6 = myConstant;

    public $var7 = array(true, false);

    View Slide

  15. Задание

    View Slide

  16. Задание
    Создайте класс SuperHero. Придумайте, какие у него
    могут быть свойства.

    View Slide

  17. extends
    class ExtendClass extends ComplicatedClass

    {

    function displayVar()

    {

    echo "Extending class\n";

    parent::displayVar();

    }

    }

    !
    $extended = new ExtendClass();

    $extended->displayVar();

    View Slide

  18. extends
    • Наследоваться можно только от одного
    класса

    • Свойства и методы могут быть
    переопределены (если не заданы как final
    в родителе)

    • Сигнатура параметров переопределямых
    методов должна совпадать (кроме
    конструктора), иначе — E_STRICT

    View Slide

  19. extends

    View Slide

  20. Задание
    Создайте базовый класс Сharacter. Унаследуйте от
    него наш SuperHero и новый класс SuperVillain.
    Вынесите в Character общие свойства для героев и
    злодеев, а в них оставьте только уникальные поля.

    View Slide

  21. Задание

    View Slide

  22. Константы
    class MyClass

    {

    const constant = 'constant value';

    !
    function showConstant() {

    echo self::constant . "\n";

    }

    }

    !
    echo MyClass::constant . "\n";

    !
    $classname = "MyClass";

    echo $classname::constant . "\n"; // As of PHP 5.3.0

    !
    $class = new MyClass();

    $class->showConstant();

    !
    echo $class::constant."\n"; // As of PHP 5.3.0

    View Slide

  23. Константы
    • доступны как часть класса

    • доступны во всех областях видимости

    • могут содержать только скалярные
    значения

    • способствуют более чистому коду

    • работают быстрее констант,
    определенных через define()

    View Slide

  24. Constructor

    View Slide

  25. Constructor
    class BaseClass {

    function __construct() {

    print "In BaseClass constructor\n";

    }

    }

    !
    class SubClass extends BaseClass {

    function __construct() {

    parent::__construct();

    print "In SubClass constructor\n";

    }

    }

    !
    class OtherSubClass extends BaseClass {

    // inherits BaseClass's constructor

    }

    View Slide

  26. Constructor
    // In BaseClass constructor

    $obj = new BaseClass();

    !
    // In BaseClass constructor

    // In SubClass constructor

    $obj = new SubClass();

    !
    // In BaseClass constructor

    $obj = new OtherSubClass();

    View Slide

  27. Constructor
    • вызывается при создании объекта

    • родительский конструктор надо вызывать
    явно: parent::__construct()
    • если не переопределен, наследуется от
    класса родителя (если там он не private)

    • при переопределении параметры могут
    меняться

    View Slide

  28. Задание
    Добавьте нашим героям и злодеям конструкторы,
    чтобы при создании объекта задавались основные
    свойства. Общие параметры должны задаваться
    только в конструкторе родительского класса.

    View Slide

  29. Destructor
    class MyDestructableClass {

    function __construct() {

    print "In constructor\n";

    $this->name = "MyDestructableClass";

    }

    !
    function __destruct() {

    print "Destroying " . $this->name . "\n";

    }

    }

    !
    $obj = new MyDestructableClass();

    View Slide

  30. Destructor
    • будет вызван, как только на объект не
    останется ссылок

    • либо при завершении работы скрипта

    • родительский destructor надо вызывать
    явно: parent::__destruct()

    • будет вызван даже при остановке
    скрипта с помощью exit()

    View Slide

  31. Destructor

    View Slide

  32. PPP & F
    • Public

    • Private

    • Protected

    • Final — может применять к методам и
    классу целиком

    View Slide

  33. PPP
    class MyClass

    {

    public $public = 'Public';

    protected $protected = 'Protected';

    private $private = 'Private';

    !
    function printHello()

    {

    echo $this->public;

    echo $this->protected;

    echo $this->private;

    }

    }

    View Slide

  34. PPP
    $obj = new MyClass();

    echo $obj->public; // Works

    echo $obj->protected; // Fatal Error

    echo $obj->private; // Fatal Error

    $obj->printHello(); // Shows Public, Protected and Private

    View Slide

  35. PPP
    class MyClass2 extends MyClass

    {

    // We can redeclare the public and protected method, but not private

    protected $protected = 'Protected2';

    !
    function printHello()

    {

    echo $this->public;

    echo $this->protected;

    echo $this->private;

    }

    }

    View Slide

  36. PPP
    $obj2 = new MyClass2();

    echo $obj2->public; // Works

    echo $obj2->private; // Undefined

    echo $obj2->protected; // Fatal Error

    $obj2->printHello(); // Shows Public, Protected2, Undefined

    View Slide

  37. Задание.
    Проверьте, правильно ли у вас расставлены уровни
    доступа у свойств и методов в созданных ранее
    классах. Добавьте свойств с недостающими
    уровнями видимости.

    View Slide

  38. Задание.
    На удивление в PHP можно получить доступ к
    private и protected свойствам и методам объкта из
    объекта такого же класса.

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

    View Slide

  39. Paamayim Nekudotayim
    ::

    View Slide

  40. static

    View Slide

  41. static

    class Foo

    {

    public static $my_static = 'foo';

    !
    public function staticValue() {

    return self::$my_static;

    }

    }

    !
    class Bar extends Foo

    {

    public function fooStatic() {

    return parent::$my_static;

    }

    }

    View Slide

  42. static
    print Foo::$my_static . "\n";

    !
    $foo = new Foo();

    print $foo->staticValue() . "\n";

    print $foo->my_static . "\n"; // Undefined "Property" my_static

    !
    print $foo::$my_static . "\n";

    $classname = 'Foo';

    print $classname::$my_static . "\n"; // As of PHP 5.3.0

    !
    print Bar::$my_static . "\n";

    $bar = new Bar();

    print $bar->fooStatic() . "\n";

    View Slide

  43. static
    • доступны именно как часть класса

    • вызываются без создания объекта

    • вызов статичного свойства с помощью
    объектной нотации — Notice

    • по умолчанию public

    • использовать $this внутри статичных
    методов нельзя

    View Slide

  44. abstract

    View Slide

  45. abstract
    abstract class AbstractClass

    {

    // Force Extending class to define this method

    abstract protected function getValue();

    abstract protected function prefixValue($prefix);

    !
    // Common method

    public function printOut() {

    print $this->getValue() . "\n";

    }

    }

    View Slide

  46. abstract
    class ConcreteClass1 extends AbstractClass

    {

    protected function getValue() {

    return "ConcreteClass1";

    }

    !
    public function prefixValue($prefix) {

    return "{$prefix}ConcreteClass1";

    }

    }

    View Slide

  47. abstract
    • Класс должен быть объявлен
    абстрактным, если содержит или
    наследует хотя бы один абстрактный
    метод без имплементации

    • класс может иметь только одного предка

    • реализует ограничения для дизайна
    группы классов

    View Slide

  48. Задание.
    Сделайте класс Character абстрактным и объявите в
    нем несколько абстрактных методов методов и
    один-два уже реализованных (общих для героев и
    злодеев). Абстрактные методы реализуйте в классах-
    наследниках.

    Например: saveWorld(), fight(), makeSomethingBad(),
    muahahahaha(), think(), putOnMask(), useSuperPower(),
    sayCatchPhrase() и т.д.

    View Slide

  49. interface
    Интерфейсы позволяют создавать код, который
    определяет, какие методы должны реализовывать
    классы без необходимости определять саму
    реализацию методов.

    View Slide

  50. interface

    View Slide

  51. interface
    interface iTemplate

    {

    public function setVariable($name, $var);

    public function getHtml($template);

    }

    View Slide

  52. interface
    class Template implements iTemplate

    {

    private $vars = array();



    public function setVariable($name, $var)

    {

    $this->vars[$name] = $var;

    }



    public function getHtml($template)

    {

    foreach($this->vars as $name => $value) {

    $template = str_replace('{' . $name . '}', $value, $template);

    }

    return $template;

    }

    }

    View Slide

  53. interface
    • все метода интерфейса — public, иначе
    просто бессмысленно :)

    • класс может имплементить больше
    одного интерфейса

    • но у этих интерфейсов не должно быть
    методов с одинаковыми именами

    View Slide

  54. interface
    • интерфейсы могут наследоваться

    • интерфейсы могут содержать константы

    • сигнатуры методов интерфейса и класса
    должны совпадать

    View Slide

  55. Задание.
    Создайте два интерфейса: один супергеройский,
    другой суперзлодейский. Объявите в них
    обязательные методы. Пусть наши классы будут
    реализовывать каждый свой интерфейс.

    !
    Варианты методов: doEvil(), muahaha(), scaryFace(),
    saveTheWorldAgainBeforeBreakfast()

    View Slide

  56. Instanceof
    Позволяет определить является ли объект
    экземпляром класса или интерфейса с учетом
    наследования.

    View Slide

  57. Instanceof

    View Slide

  58. Instanceof
    class ParentClass

    {

    }

    !
    class MyClass extends ParentClass

    {

    }

    !
    $a = new MyClass();

    !
    var_dump($a instanceof MyClass);

    var_dump($a instanceof ParentClass);

    View Slide

  59. Instanceof
    interface MyInterface

    {

    }

    !
    class MyClass implements MyInterface

    {

    }

    !
    $a = new MyClass();

    !
    var_dump($a instanceof MyClass);

    var_dump($a instanceof MyInterface);

    View Slide

  60. Задание.
    У нас уже есть три класса и два интерфейса.
    Создайте несколько объектов и проверьте
    являются ли они инстансами каждого класса и
    интерфейса.

    View Slide

  61. Object Iteration
    class MyClass

    {

    public $var1 = 'value 1';

    public $var2 = 'value 2';

    public $var3 = 'value 3';

    !
    protected $protected = 'protected var';

    private $private = 'private var';

    !
    function iterateVisible() {

    echo "MyClass::iterateVisible:\n";

    foreach($this as $key => $value) {

    print "$key => $value\n";

    }

    }

    }

    View Slide

  62. Object Iteration
    $class = new MyClass();

    !
    foreach($class as $key => $value) {

    print "$key => $value\n";

    }

    echo "\n";

    !
    !
    $class->iterateVisible();

    View Slide

  63. Magic methods

    View Slide

  64. Magic methods
    • __toString()

    • __call()

    • __get()

    • __set()

    View Slide

  65. Задание.
    Задайте классам героев и злодеев магические
    методы. Пусть в них просто выводится что-нибудь
    жизнеутверждающее и нетленное.

    View Slide

  66. Клонирование

    View Slide

  67. Клонирование
    $class = new MyClass();

    !
    $copy = $class;

    !
    do_some_stuff($copy);

    !
    /*

    $class и $copy остались ссылками на один и тот же объект и будут
    изменены оба

    */

    View Slide

  68. Клонирование
    $class = new MyClass();

    !
    $copy = clone $class;

    !
    do_some_stuff($copy);

    !
    /*

    $class и $copy будут разными объектами. Изменения в $copy не будут
    влиять на изменения в $class

    */

    View Slide

  69. Клонирование
    public function __clone() {

    /*

    если при клонировании нужны особые условия

    */

    }

    View Slide

  70. Сравнение объектов
    • == — одинаковые атрибуты, значения и
    реализуют один и тот же класс

    • === — ссылки на один и тот же инстанс
    класса

    View Slide

  71. Namespaces

    View Slide

  72. Проблемы
    • Коллизии имен между пользовательским
    кодом и классами/функциями/
    константами самого PHP или стороннего
    используемого кода.

    • Слишком длинные имена, которыми
    решалась предыдущия проблема

    View Slide

  73. Namespaces

    namespace my\name;

    !
    class MyClass {}

    function myfunction() {}

    const MYCONST = 1;

    !
    $a = new MyClass;

    $c = new \my\name\MyClass;

    View Slide

  74. Namespaces
    $a = strlen('hi');

    !
    $d = namespace\MYCONST;

    !
    $d = __NAMESPACE__ . '\MYCONST';

    echo constant($d);

    View Slide

  75. Namespaces
    • namespace — первое, что есть в php
    файле после открывающего тэга

    • Один и тот же namespace может быть
    объявлен в нескольких файлах

    • Пространства имен могут формировать
    иерархию

    View Slide

  76. Namespaces
    • к глобальному пространству имен всегда
    можно обратиться добавив перед
    вызовом \

    • __NAMESPACE__ — константа
    содержащая имя текущего пространства
    имен

    View Slide

  77. Импортируем
    use My\Full\Classname as Another, My\Full\NSname;

    !
    $obj = new Another; // создает объект класса My\Full\Classname

    !
    NSname\subns\func(); // вызывает функцию My\Full\NSname\subns\func

    View Slide

  78. Интерпретируем
    • имя указано без\ в начале — класс будет
    искаться в текущем namespace

    • при его отсутствии — Fatal error

    • Для функций и констант без полного
    имени ненайденных в текущем
    namespace будет попытка найти их в
    глобальном пространстве имен (fallback).

    View Slide

  79. PSR-0
    • \Zend\Acl => /vendor/Zend/Acl.php

    • \Doctrine\Common\IsolatedClassLoader
    => /vendor/Doctrine/Common/
    IsolatedClassLoader.php

    • https://github.com/php-fig/fig-standards/
    blob/master/accepted/PSR-0.md

    View Slide

  80. Интерпретируем

    View Slide

  81. Задание.
    Организуем наш код как взрослые.

    Для приложения — отдельный каталог epicoop

    Весь код классов — в epicoop/src.

    Главный namespace — Epicphp

    Расположение классов соответствует PSR-0

    index.php — epicoop/web

    В index.php подключаем все нужные классы

    View Slide

  82. Exceptions

    View Slide

  83. Exceptions
    function inverse($x) {

    if (!$x) {

    throw new Exception('Division by zero.');

    }

    else return 1/$x;

    }

    !
    try {

    echo inverse(5) . "\n";

    echo inverse(0) . "\n";

    } catch (Exception $e) {

    echo 'Caught exception: ', $e->getMessage(), "\n";

    }

    View Slide

  84. Exceptions

    View Slide

  85. Exceptions
    • Унифицированный метод обработки
    ошибок

    • По сути являются объектами,
    создаваемыми (“выбрасываемыми”) в
    случае ошибки

    • Все исключения в throw должны быть
    инстансами класса Exception или его
    наследников

    View Slide

  86. Exceptions
    • Каждый try должен иметь хотя бы один
    catch

    • блоков catch может быть несколько (для
    разных классов исключений)

    • После “выкинутого” код не выполняется
    до первого найденного catch

    • Исключение не поймано — Fatal error

    View Slide

  87. Exceptions
    • Внутренние функции PHP используют
    error reporting и только новые ООП
    расширения исользуют exceptions, но это
    можно переопределить

    • http://www.php.net/manual/en/
    spl.exceptions.php

    View Slide

  88. Autoloading

    View Slide

  89. Проблемы
    • Много классов в ООП приложениях

    • Как правило, один класс — один файл

    • До использования каждый класс надо
    подключить

    • Получались частоколы require и include

    • Много ошибок из-за забытых файлов

    View Slide

  90. Проблемы

    View Slide

  91. __autoload()
    function __autoload($class_name)

    {

    require_once "/www/library/{$class_name}.php";

    }

    !
    $a = new friend();

    View Slide

  92. __autoload()
    function __autoload($name) {

    echo "Want to load $name.\n";

    throw new Exception("Unable to load $name.");

    }

    !
    try {

    $obj = new NonLoadableClass();

    } catch (Exception $e) {

    echo $e->getMessage(), "\n";

    }

    View Slide

  93. spl_autoload_register
    Позволяет сделать несколько автолоадеров на случай разных
    концепций загрузки файлов.

    !
    function my_autoloader($class) {

    include 'classes/' . $class . '.class.php';

    }

    !
    spl_autoload_register('my_autoloader');

    View Slide

  94. Задание.
    Убираем из index.php все require и создаем
    функцию автолоадинга. Проверяем, что при
    создании объектов классов ошибок нет.

    View Slide

  95. Standard PHP Library
    (SPL)

    View Slide

  96. SPL
    Входит в состав PHP и содержит коллекцию
    полезных классов и интерфейсов.

    View Slide

  97. SPL
    • Iterators

    • Datastructures

    • Interfaces

    • Exceptions

    • “и кое-что еще...” ©

    • http://php.net/spl

    View Slide

  98. Управление
    зависимостями

    View Slide

  99. Проблемы
    • На PHP написано много кода

    • На самом деле много

    • Вам столько даже представить сложно

    • И я не шучу

    • С чего бы мне шутить

    View Slide

  100. Проблемы
    • Посреди тон кода есть куча полезностей

    • Фреймворки

    • Библиотеки

    • Компоненты

    • Да, большинство простых проблем уже
    решены за вас

    View Slide

  101. Проблемы
    • И вы будете использовать чужие
    фреймворки, библиотеки, компоненты...

    • Много, это точно

    • Но их же надо как-то искать?

    • Устанавливать?

    • Обновлять?

    View Slide

  102. PEAR?

    View Slide

  103. Fuck PEAR!

    View Slide

  104. View Slide

  105. Composer
    Composer является блестящим менеджером
    зависимостей для PHP. Укажите список
    зависимостей вашего проекта, в файле
    composer.json и с несколькими простыми
    командами, Composer автоматически скачает
    зависимости вашего проекта и установит
    автозагрузку для вас.

    View Slide

  106. Composer
    • Множество совместимых библиотек

    • Их можно искать: https://packagist.org/

    • Взрывное развитие и популярность у
    разработчиков

    • Если вашей библиотеки нет в packagist и
    ее не поставить через composer, то
    вашей библиотеки просто нет

    View Slide

  107. Composer
    curl -s https://getcomposer.org/installer | php

    !
    php composer.phar require twig/twig:~1.8

    !
    php composer.phar install

    View Slide

  108. Composer

    require 'vendor/autoload.php';

    !
    /*

    проблема автолоадинга только что была решена за вас бесплатно и без
    СМС!

    */

    View Slide

  109. composer.json
    {

    "require": {

    "silex/silex": "1.0.*",

    "swiftmailer/swiftmailer": ">=4.1.2,<4.2-dev",

    "twig/twig": ">=1.8,<2.0-dev",

    "symfony/twig-bridge": "2.1.*",

    "symfony/form": "2.1.*",

    "symfony/validator": "2.1.*",

    "symfony/config": "2.1.*",

    "symfony/translation": "2.1.*",

    "rmzamora/google-api-php": "dev-master",

    "zendframework/zendgdata": "2.0.*",

    "symfony/security": "2.1.*"

    },

    "minimum-stability": "dev",

    !
    "autoload": {

    "psr-0": {

    "App": "src/"

    }

    }

    }

    View Slide

  110. Composer
    • composer.json

    • composer.lock

    • php composer.phar update

    • http://getcomposer.org/doc/00-intro.md

    • Composer умеет ставить либы из PEAR

    View Slide

  111. Задание.
    Установите композер в наш epicoop.

    Найдите в packagist symfony/finder, symfony/config,
    symfony/http-foundation. Установите их через
    composer.

    View Slide

  112. Дизайн и паттерны

    View Slide

  113. Дизайн и паттерны

    View Slide

  114. Code Reuse
    • Мы решаем одни и те же проблемы
    каждый день

    • Мы решаем те же пробемы, что и наши
    “соседи” каждый день

    • Мы решаем одинаковые проблемы на
    разных проектах

    • И мы ленивые, но хотим делать хорошо!

    View Slide

  115. Дизайн и паттерны
    • Правильные и конкретные решения для
    общих проблем

    • Общий язык для общения между
    разработчиками

    View Slide

  116. Singleton
    public static function getInstance()

    {

    static $instance = null;

    if (null === $instance) {

    $instance = new static;

    }

    !
    return $instance;

    }

    !
    protected function __construct()

    {

    }

    View Slide

  117. Singleton
    $obj = Singleton::getInstance();

    \var_dump($obj === Singleton::getInstance()); // bool(true)

    View Slide

  118. Singleton
    • убедиться, что в системе только один
    инстанс определенного класса

    • применения: обертки соединений (база
    данных, файлы, внешние источники
    данных)

    • Не рекомендуется к использованию в
    последнее время

    View Slide

  119. Registry
    • Расширение Singleton

    • По сути явлется хранилищем для данных
    и инстансов других объектов

    • И обеспечивает, что это хранилище в
    системе одно

    • Zend_Registry

    View Slide

  120. Factory
    • Предоставляет собой общий интерфейс
    к набору классов со схожей
    функциональностью, но разной начинкой

    • Создает инстанс нужного класса

    • например, фабрика для выбора
    хранилища данных, службы доставки,
    платежной системы

    View Slide

  121. Factory

    View Slide

  122. Front controller
    • Одна (!) точка входа для всех запрсов
    приложения

    • Совсем одна

    • Одна-одинешенька

    • Как Уилл Смит в «Я Легенда»

    • Пока не встретил женщину, из-за
    которой умер

    View Slide

  123. Front controller

    View Slide

  124. Front controller
    • index.php

    • + настройка сервера (например, .htaccess)

    • код, ответственный за загрузку
    зависимостей, обработку запроса,
    отправку ответа, весь он в одном месте

    • способствует модульности

    View Slide

  125. MVC
    • во всех фреймворках страны

    • т.е. во всех современных фреймворках на
    самом деле

    View Slide

  126. MVC
    • Model

    • View

    • Controller

    View Slide

  127. MVC
    • Model — данные и обработка

    • View — шаблоны (html, xml, markup...) и
    никакой логики

    • Controller — обработка запроса,
    отправка данных из модели во вьюшку

    View Slide

  128. MVC

    View Slide

  129. MVC

    View Slide

  130. Задание.
    Переделайте ваше CRUD приложение с
    использованием объектов и паттернов.

    !
    Код вне объектов может быть только в index.php.

    Html должен быть в отдельных файлах. Логики там
    содержаться не должно, максимум вывод
    переменных, циклы для списков и if необходимые
    для определения логики вывода.

    !
    Не бойтесь ошибиться. Не попробовав, вы никогда
    не поймете, как оно работает на самом деле.

    View Slide

  131. Задание.
    Переделайте ваше CRUD приложение с
    использованием объектов и паттернов.

    !
    Код вне объектов может быть только в index.php.

    Html должен быть в отдельных файлах. Логики там
    содержаться не должно.

    !
    Не бойтесь ошибиться. Не попробовав, вы никогда
    не поймете, как оно.

    View Slide