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

Epic PHP #5

101b5adab18a468a3dfe63f77980ccb9?s=47 Roma
March 13, 2014

Epic PHP #5

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

101b5adab18a468a3dfe63f77980ccb9?s=128

Roma

March 13, 2014
Tweet

Transcript

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

  2. Основы ООП

  3. Объекты? Стратегию ООП лучше всего описать как смещение приоритетов в

    процессе программирования от функциональности приложения к структурам данных. Это позволяет программисту моделировать в создаваемых приложениях реальные объекты и ситуации.
  4. ООП • Инкапсуляция • Полиморфизм • Наследование

  5. ООП

  6. Class class ComplicatedClass { ! public $someVar = 'a default

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

    (методы) • Название класса не может быть зарезервированным словом PHP • Название может начинаться с буквы или символа подчеркивания и состоять из букв, цифр и _.
  8. $this Псевдопеременная, доступная, когда метод вызывается в контексте объекта. Является

    ссылкой на вызывающий объект.
  9. $this

  10. new $instance = new ComplicatedClass(); ! $className = 'Foo'; $instance

    = new $className(); // Foo()
  11. new • Создает экземпляр класса • В контексте класса можно

    создать объект, используя new self или new parent
  12. Class vs Object?

  13. Class vs Object?

  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);
  15. Задание

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

    свойства.
  17. extends class ExtendClass extends ComplicatedClass { function displayVar() { echo

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

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

  20. Задание Создайте базовый класс Сharacter. Унаследуйте от него наш SuperHero

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

  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
  23. Константы • доступны как часть класса • доступны во всех

    областях видимости • могут содержать только скалярные значения • способствуют более чистому коду • работают быстрее констант, определенных через define()
  24. Constructor

  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 }
  26. Constructor // In BaseClass constructor $obj = new BaseClass(); !

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

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

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

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

    ссылок • либо при завершении работы скрипта • родительский destructor надо вызывать явно: parent::__destruct() • будет вызван даже при остановке скрипта с помощью exit()
  31. Destructor

  32. PPP & F • Public • Private • Protected •

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

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

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

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

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

  40. static

  41. 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; } }
  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";
  43. static • доступны именно как часть класса • вызываются без

    создания объекта • вызов статичного свойства с помощью объектной нотации — Notice • по умолчанию public • использовать $this внутри статичных методов нельзя
  44. abstract

  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"; } }
  46. abstract class ConcreteClass1 extends AbstractClass { protected function getValue() {

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

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

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

    реализовывать классы без необходимости определять саму реализацию методов.
  50. interface

  51. interface interface iTemplate { public function setVariable($name, $var); public function

    getHtml($template); }
  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; } }
  53. interface • все метода интерфейса — public, иначе просто бессмысленно

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

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

    них обязательные методы. Пусть наши классы будут реализовывать каждый свой интерфейс. ! Варианты методов: doEvil(), muahaha(), scaryFace(), saveTheWorldAgainBeforeBreakfast()
  56. Instanceof Позволяет определить является ли объект экземпляром класса или интерфейса

    с учетом наследования.
  57. Instanceof

  58. Instanceof class ParentClass { } ! class MyClass extends ParentClass

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

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

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

    => $value) { print "$key => $value\n"; } echo "\n"; ! ! $class->iterateVisible();
  63. Magic methods

  64. Magic methods • __toString() • __call() • __get() • __set()

  65. Задание. Задайте классам героев и злодеев магические методы. Пусть в

    них просто выводится что-нибудь жизнеутверждающее и нетленное.
  66. Клонирование

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

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

    ! do_some_stuff($copy); ! /* $class и $copy будут разными объектами. Изменения в $copy не будут влиять на изменения в $class */
  69. Клонирование public function __clone() { /* если при клонировании нужны

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

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

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

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

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

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

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

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

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

    искаться в текущем namespace • при его отсутствии — Fatal error • Для функций и констант без полного имени ненайденных в текущем namespace будет попытка найти их в глобальном пространстве имен (fallback).
  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
  80. Интерпретируем

  81. Задание. Организуем наш код как взрослые. Для приложения — отдельный

    каталог epicoop Весь код классов — в epicoop/src. Главный namespace — Epicphp Расположение классов соответствует PSR-0 index.php — epicoop/web В index.php подключаем все нужные классы
  82. Exceptions

  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"; }
  84. Exceptions

  85. Exceptions • Унифицированный метод обработки ошибок • По сути являются

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

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

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

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

    один класс — один файл • До использования каждый класс надо подключить • Получались частоколы require и include • Много ошибок из-за забытых файлов
  90. Проблемы

  91. __autoload() function __autoload($class_name) { require_once "/www/library/{$class_name}.php"; } ! $a =

    new friend();
  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"; }
  93. spl_autoload_register Позволяет сделать несколько автолоадеров на случай разных концепций загрузки

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

    Проверяем, что при создании объектов классов ошибок нет.
  95. Standard PHP Library (SPL)

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

    и интерфейсов.
  97. SPL • Iterators • Datastructures • Interfaces • Exceptions •

    “и кое-что еще...” © • http://php.net/spl
  98. Управление зависимостями

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

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

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

    • Много, это точно • Но их же надо как-то искать? • Устанавливать? • Обновлять?
  102. PEAR?

  103. Fuck PEAR!

  104. None
  105. Composer Composer является блестящим менеджером зависимостей для PHP. Укажите список

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

    • Взрывное развитие и популярность у разработчиков • Если вашей библиотеки нет в packagist и ее не поставить через composer, то вашей библиотеки просто нет
  107. Composer curl -s https://getcomposer.org/installer | php ! php composer.phar require

    twig/twig:~1.8 ! php composer.phar install
  108. Composer <?php require 'vendor/autoload.php'; ! /* проблема автолоадинга только что

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

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

    symfony/config, symfony/http-foundation. Установите их через composer.
  112. Дизайн и паттерны

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

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

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

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

    if (null === $instance) { $instance = new static; } ! return $instance; } ! protected function __construct() { }
  117. Singleton $obj = Singleton::getInstance(); \var_dump($obj === Singleton::getInstance()); // bool(true)

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

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

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

    схожей функциональностью, но разной начинкой • Создает инстанс нужного класса • например, фабрика для выбора хранилища данных, службы доставки, платежной системы
  121. Factory

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

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

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

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

    современных фреймворках на самом деле
  126. MVC • Model • View • Controller

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

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

  129. MVC

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

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

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