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. Объекты? Стратегию ООП лучше всего описать как смещение приоритетов в

    процессе программирования от функциональности приложения к структурам данных. Это позволяет программисту моделировать в создаваемых приложениях реальные объекты и ситуации.
  2. Class class ComplicatedClass { ! public $someVar = 'a default

    value'; ! public function displayVar() { echo $this->someVar; } }
  3. Class • Может содержать свои константы, переменные (свойства) и функции

    (методы) • Название класса не может быть зарезервированным словом PHP • Название может начинаться с буквы или символа подчеркивания и состоять из букв, цифр и _.
  4. new • Создает экземпляр класса • В контексте класса можно

    создать объект, используя new self или new parent
  5. Свойства // 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);
  6. extends class ExtendClass extends ComplicatedClass { function displayVar() { echo

    "Extending class\n"; parent::displayVar(); } } ! $extended = new ExtendClass(); $extended->displayVar();
  7. extends • Наследоваться можно только от одного класса • Свойства

    и методы могут быть переопределены (если не заданы как final в родителе) • Сигнатура параметров переопределямых методов должна совпадать (кроме конструктора), иначе — E_STRICT
  8. Задание Создайте базовый класс Сharacter. Унаследуйте от него наш SuperHero

    и новый класс SuperVillain. Вынесите в Character общие свойства для героев и злодеев, а в них оставьте только уникальные поля.
  9. Константы 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
  10. Константы • доступны как часть класса • доступны во всех

    областях видимости • могут содержать только скалярные значения • способствуют более чистому коду • работают быстрее констант, определенных через define()
  11. 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 }
  12. Constructor // In BaseClass constructor $obj = new BaseClass(); !

    // In BaseClass constructor // In SubClass constructor $obj = new SubClass(); ! // In BaseClass constructor $obj = new OtherSubClass();
  13. Constructor • вызывается при создании объекта • родительский конструктор надо

    вызывать явно: parent::__construct() • если не переопределен, наследуется от класса родителя (если там он не private) • при переопределении параметры могут меняться
  14. Задание Добавьте нашим героям и злодеям конструкторы, чтобы при создании

    объекта задавались основные свойства. Общие параметры должны задаваться только в конструкторе родительского класса.
  15. Destructor class MyDestructableClass { function __construct() { print "In constructor\n";

    $this->name = "MyDestructableClass"; } ! function __destruct() { print "Destroying " . $this->name . "\n"; } } ! $obj = new MyDestructableClass();
  16. Destructor • будет вызван, как только на объект не останется

    ссылок • либо при завершении работы скрипта • родительский destructor надо вызывать явно: parent::__destruct() • будет вызван даже при остановке скрипта с помощью exit()
  17. PPP & F • Public • Private • Protected •

    Final — может применять к методам и классу целиком
  18. PPP class MyClass { public $public = 'Public'; protected $protected

    = 'Protected'; private $private = 'Private'; ! function printHello() { echo $this->public; echo $this->protected; echo $this->private; } }
  19. 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
  20. 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; } }
  21. PPP $obj2 = new MyClass2(); echo $obj2->public; // Works echo

    $obj2->private; // Undefined echo $obj2->protected; // Fatal Error $obj2->printHello(); // Shows Public, Protected2, Undefined
  22. Задание. Проверьте, правильно ли у вас расставлены уровни доступа у

    свойств и методов в созданных ранее классах. Добавьте свойств с недостающими уровнями видимости.
  23. Задание. На удивление в PHP можно получить доступ к private

    и protected свойствам и методам объкта из объекта такого же класса. ! Попробуйте сами написать код, подтверждающий это. Если не получится, то найдите в документации и напишите подобный.
  24. static <?php 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; } }
  25. 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";
  26. static • доступны именно как часть класса • вызываются без

    создания объекта • вызов статичного свойства с помощью объектной нотации — Notice • по умолчанию public • использовать $this внутри статичных методов нельзя
  27. 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"; } }
  28. abstract class ConcreteClass1 extends AbstractClass { protected function getValue() {

    return "ConcreteClass1"; } ! public function prefixValue($prefix) { return "{$prefix}ConcreteClass1"; } }
  29. abstract • Класс должен быть объявлен абстрактным, если содержит или

    наследует хотя бы один абстрактный метод без имплементации • класс может иметь только одного предка • реализует ограничения для дизайна группы классов
  30. Задание. Сделайте класс Character абстрактным и объявите в нем несколько

    абстрактных методов методов и один-два уже реализованных (общих для героев и злодеев). Абстрактные методы реализуйте в классах- наследниках. Например: saveWorld(), fight(), makeSomethingBad(), muahahahaha(), think(), putOnMask(), useSuperPower(), sayCatchPhrase() и т.д.
  31. interface Интерфейсы позволяют создавать код, который определяет, какие методы должны

    реализовывать классы без необходимости определять саму реализацию методов.
  32. 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; } }
  33. interface • все метода интерфейса — public, иначе просто бессмысленно

    :) • класс может имплементить больше одного интерфейса • но у этих интерфейсов не должно быть методов с одинаковыми именами
  34. interface • интерфейсы могут наследоваться • интерфейсы могут содержать константы

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

    них обязательные методы. Пусть наши классы будут реализовывать каждый свой интерфейс. ! Варианты методов: doEvil(), muahaha(), scaryFace(), saveTheWorldAgainBeforeBreakfast()
  36. Instanceof class ParentClass { } ! class MyClass extends ParentClass

    { } ! $a = new MyClass(); ! var_dump($a instanceof MyClass); var_dump($a instanceof ParentClass);
  37. Instanceof interface MyInterface { } ! class MyClass implements MyInterface

    { } ! $a = new MyClass(); ! var_dump($a instanceof MyClass); var_dump($a instanceof MyInterface);
  38. Задание. У нас уже есть три класса и два интерфейса.

    Создайте несколько объектов и проверьте являются ли они инстансами каждого класса и интерфейса.
  39. 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"; } } }
  40. Object Iteration $class = new MyClass(); ! foreach($class as $key

    => $value) { print "$key => $value\n"; } echo "\n"; ! ! $class->iterateVisible();
  41. Задание. Задайте классам героев и злодеев магические методы. Пусть в

    них просто выводится что-нибудь жизнеутверждающее и нетленное.
  42. Клонирование $class = new MyClass(); ! $copy = $class; !

    do_some_stuff($copy); ! /* $class и $copy остались ссылками на один и тот же объект и будут изменены оба */
  43. Клонирование $class = new MyClass(); ! $copy = clone $class;

    ! do_some_stuff($copy); ! /* $class и $copy будут разными объектами. Изменения в $copy не будут влиять на изменения в $class */
  44. Сравнение объектов • == — одинаковые атрибуты, значения и реализуют

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

    самого PHP или стороннего используемого кода. • Слишком длинные имена, которыми решалась предыдущия проблема
  46. Namespaces <?php namespace my\name; ! class MyClass {} function myfunction()

    {} const MYCONST = 1; ! $a = new MyClass; $c = new \my\name\MyClass;
  47. Namespaces $a = strlen('hi'); ! $d = namespace\MYCONST; ! $d

    = __NAMESPACE__ . '\MYCONST'; echo constant($d);
  48. Namespaces • namespace — первое, что есть в php файле

    после открывающего тэга • Один и тот же namespace может быть объявлен в нескольких файлах • Пространства имен могут формировать иерархию
  49. Namespaces • к глобальному пространству имен всегда можно обратиться добавив

    перед вызовом \ • __NAMESPACE__ — константа содержащая имя текущего пространства имен
  50. Импортируем use My\Full\Classname as Another, My\Full\NSname; ! $obj = new

    Another; // создает объект класса My\Full\Classname ! NSname\subns\func(); // вызывает функцию My\Full\NSname\subns\func
  51. Интерпретируем • имя указано без\ в начале — класс будет

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

    каталог epicoop Весь код классов — в epicoop/src. Главный namespace — Epicphp Расположение классов соответствует PSR-0 index.php — epicoop/web В index.php подключаем все нужные классы
  53. 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"; }
  54. Exceptions • Унифицированный метод обработки ошибок • По сути являются

    объектами, создаваемыми (“выбрасываемыми”) в случае ошибки • Все исключения в throw должны быть инстансами класса Exception или его наследников
  55. Exceptions • Каждый try должен иметь хотя бы один catch

    • блоков catch может быть несколько (для разных классов исключений) • После “выкинутого” код не выполняется до первого найденного catch • Исключение не поймано — Fatal error
  56. Exceptions • Внутренние функции PHP используют error reporting и только

    новые ООП расширения исользуют exceptions, но это можно переопределить • http://www.php.net/manual/en/ spl.exceptions.php
  57. Проблемы • Много классов в ООП приложениях • Как правило,

    один класс — один файл • До использования каждый класс надо подключить • Получались частоколы require и include • Много ошибок из-за забытых файлов
  58. __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"; }
  59. spl_autoload_register Позволяет сделать несколько автолоадеров на случай разных концепций загрузки

    файлов. ! function my_autoloader($class) { include 'classes/' . $class . '.class.php'; } ! spl_autoload_register('my_autoloader');
  60. Задание. Убираем из index.php все require и создаем функцию автолоадинга.

    Проверяем, что при создании объектов классов ошибок нет.
  61. SPL • Iterators • Datastructures • Interfaces • Exceptions •

    “и кое-что еще...” © • http://php.net/spl
  62. Проблемы • На PHP написано много кода • На самом

    деле много • Вам столько даже представить сложно • И я не шучу • С чего бы мне шутить
  63. Проблемы • Посреди тон кода есть куча полезностей • Фреймворки

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

    • Много, это точно • Но их же надо как-то искать? • Устанавливать? • Обновлять?
  65. Composer Composer является блестящим менеджером зависимостей для PHP. Укажите список

    зависимостей вашего проекта, в файле composer.json и с несколькими простыми командами, Composer автоматически скачает зависимости вашего проекта и установит автозагрузку для вас.
  66. Composer • Множество совместимых библиотек • Их можно искать: https://packagist.org/

    • Взрывное развитие и популярность у разработчиков • Если вашей библиотеки нет в packagist и ее не поставить через composer, то вашей библиотеки просто нет
  67. Composer <?php require 'vendor/autoload.php'; ! /* проблема автолоадинга только что

    была решена за вас бесплатно и без СМС! */
  68. 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/" } } }
  69. Composer • composer.json • composer.lock • php composer.phar update •

    http://getcomposer.org/doc/00-intro.md • Composer умеет ставить либы из PEAR
  70. Задание. Установите композер в наш epicoop. Найдите в packagist symfony/finder,

    symfony/config, symfony/http-foundation. Установите их через composer.
  71. Code Reuse • Мы решаем одни и те же проблемы

    каждый день • Мы решаем те же пробемы, что и наши “соседи” каждый день • Мы решаем одинаковые проблемы на разных проектах • И мы ленивые, но хотим делать хорошо!
  72. Дизайн и паттерны • Правильные и конкретные решения для общих

    проблем • Общий язык для общения между разработчиками
  73. Singleton public static function getInstance() { static $instance = null;

    if (null === $instance) { $instance = new static; } ! return $instance; } ! protected function __construct() { }
  74. Singleton • убедиться, что в системе только один инстанс определенного

    класса • применения: обертки соединений (база данных, файлы, внешние источники данных) • Не рекомендуется к использованию в последнее время
  75. Registry • Расширение Singleton • По сути явлется хранилищем для

    данных и инстансов других объектов • И обеспечивает, что это хранилище в системе одно • Zend_Registry
  76. Factory • Предоставляет собой общий интерфейс к набору классов со

    схожей функциональностью, но разной начинкой • Создает инстанс нужного класса • например, фабрика для выбора хранилища данных, службы доставки, платежной системы
  77. Front controller • Одна (!) точка входа для всех запрсов

    приложения • Совсем одна • Одна-одинешенька • Как Уилл Смит в «Я Легенда» • Пока не встретил женщину, из-за которой умер
  78. Front controller • index.php • + настройка сервера (например, .htaccess)

    • код, ответственный за загрузку зависимостей, обработку запроса, отправку ответа, весь он в одном месте • способствует модульности
  79. MVC • во всех фреймворках страны • т.е. во всех

    современных фреймворках на самом деле
  80. MVC • Model — данные и обработка • View —

    шаблоны (html, xml, markup...) и никакой логики • Controller — обработка запроса, отправка данных из модели во вьюшку
  81. MVC

  82. MVC

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

    ! Код вне объектов может быть только в index.php. Html должен быть в отдельных файлах. Логики там содержаться не должно, максимум вывод переменных, циклы для списков и if необходимые для определения логики вывода. ! Не бойтесь ошибиться. Не попробовав, вы никогда не поймете, как оно работает на самом деле.
  84. Задание. Переделайте ваше CRUD приложение с использованием объектов и паттернов.

    ! Код вне объектов может быть только в index.php. Html должен быть в отдельных файлах. Логики там содержаться не должно. ! Не бойтесь ошибиться. Не попробовав, вы никогда не поймете, как оно.