Pro Yearly is on sale from $80 to $50! »

PHP7 で堅牢なコードを書く - 例外処理、表明プログラミング、契約による設計 / PHP Conference 2016

PHP7 で堅牢なコードを書く - 例外処理、表明プログラミング、契約による設計 / PHP Conference 2016

2016/11/03 @ PHPカンファレンス2016
2016/12/15 @ PHPカンファレンス2016再演イベントにて改訂
2017/06/10 @ PHPカンファレンス福岡2017にて改訂

2017/06/10 @ PHPカンファレンス福岡2017講演録画
https://www.youtube.com/watch?v=54jHDHvcYAo

9f3a83db74bee75a64b5e6ed106a775c?s=128

Takuto Wada

June 10, 2017
Tweet

Transcript

  1. ʲ࠶վగ൛ʳ 1)1Ͱݎ࿚ͳίʔυΛॻ͘ ྫ֎ॲཧɺද໌ϓϩάϥϛϯάɺܖ໿ʹΑΔઃܭ ࿨ా୎ਓ !U@XBEB Nov 03, 2016 @ PHPカンファレンス2016

    Dec 15, 2016 @ PHPカンファレンス2016再演 Jun 10, 2017 @ PHPカンファレンス福岡2017
  2. ࿨ా୎ਓ JEUXBEB !U@XBEB HJUIVCUXBEB

  3. ひとり歩きするスタンド ஫Ͱ΋ࠓ೔͸ςετͷ࿩͸͠·ͤΜ

  4. class BugRepository { public static function findAll($params) { global $CONF;

    $pdo = new PDO($CONF['dsn'], $CONF['usr'], $CONF['passwd'], [ PDO::ATTR_EMULATE_PREPARES => false ]); $sql = 'SELECT bug_id, summary, date_reported FROM Bugs WHERE assigned_to = :assignedTo AND status = :status'; $stmt = $pdo->prepare($sql); $stmt->execute($params); return $stmt->fetchAll(PDO::FETCH_CLASS, Bug::class); } } print_r(BugRepository::findAll([ 'assignedTo' => '12', 'status' => 'OPEN' ])); ஫ॻ੶ʰ42-ΞϯνύλʔϯʱͷͻͲ͍ ίʔυྫΛΞϨϯδͯ͠ॻ͍͍ͯ·͢ ɹͱ͋Δͱ͜Ζʹɺ͜Μͳίʔυ͕͋Γ·ͨ͠ # " %
  5. $ php example.php Array ( [0] => Bug Object (

    [bug_id] => 842 [summary] => 保存処理でクラッシュする [date_reported] => 2016-10-26 ) [1] => Bug Object ( [bug_id] => 5150 [summary] => XMLのサポート [date_reported] => 2016-10-26 ) [2] => Bug Object ( [bug_id] => 6060 [summary] => パフォーマンスの向上 [date_reported] => 2016-10-26 ) ) ɹॲཧ͕੒ޭ͢Δͱɺ͜Μͳײ͡ɻ
  6. ಥવͰ͕͢ ͜͜Ͱ ΫΠζͰ͢

  7. public static function findAll($params) { global $CONF; $pdo = new

    PDO($CONF['dsn'], $CONF['usr'], $CONF['passwd'], [ PDO::ATTR_EMULATE_PREPARES => false ]); $sql = 'SELECT bug_id, summary, date_reported FROM Bugs WHERE assigned_to = :assignedTo AND status = :status'; $stmt = $pdo->prepare($sql); $stmt->execute($params); return $stmt->fetchAll(PDO::FETCH_CLASS, Bug::class); } ⏰੍ݶ࣌ؒඵ ɹॲཧࣦഊͷݪҼʹͳΔՄೳੑ͕͋Δͷ͸Ͳͷߦ # " %
  8. public static function findAll($params) { global $CONF; $pdo = new

    PDO($CONF['dsn'], $CONF['usr'], $CONF['passwd'], [ PDO::ATTR_EMULATE_PREPARES => false ]); $sql = 'SELECT bug_id, summary, date_reported FROM Bugs WHERE assigned_to = :assignedTo AND status = :status'; $stmt = $pdo->prepare($sql); $stmt->execute($params); return $stmt->fetchAll(PDO::FETCH_CLASS, Bug::class); } # " % σʔλϕʔε઀ଓཱࣦ֬ഊ AVTSA AQBTTXEA౳Ωʔ໊͕มߋ͞Εͨ
  9. public static function findAll($params) { global $CONF; $pdo = new

    PDO($CONF['dsn'], $CONF['usr'], $CONF['passwd'], [ PDO::ATTR_EMULATE_PREPARES => false ]); $sql = 'SELECT bug_id, summary, date_reported FROM Bugs WHERE assigned_to = :assignedTo AND status = :status'; $stmt = $pdo->prepare($sql); $stmt->execute($params); return $stmt->fetchAll(PDO::FETCH_CLASS, Bug::class); } # " % ςʔϒϧ໊΍ΧϥϜ໊͕୭͔ʹมߋ͞Εͨ  ͜͜Ͱ σʔλϕʔε઀ଓΤϥʔ Fatal error: Call to a member function execute() on a non-object
  10. public static function findAll($params) { global $CONF; $pdo = new

    PDO($CONF['dsn'], $CONF['usr'], $CONF['passwd'], [ PDO::ATTR_EMULATE_PREPARES => false ]); $sql = 'SELECT bug_id, summary, date_reported FROM Bugs WHERE assigned_to = :assignedTo AND status = :status'; $stmt = $pdo->prepare($sql); $stmt->execute($params); return $stmt->fetchAll(PDO::FETCH_CLASS, Bug::class); } # " % QBSBNT͕OVMM QBSBNTͷΩʔ໊΍਺ͷෆҰக QBSBNTͷ஋͕จࣈྻʹม׵ෆೳ  ͜͜Ͱ σʔλϕʔε઀ଓΤϥʔ
  11. public static function findAll($params) { global $CONF; $pdo = new

    PDO($CONF['dsn'], $CONF['usr'], $CONF['passwd'], [ PDO::ATTR_EMULATE_PREPARES => false ]); $sql = 'SELECT bug_id, summary, date_reported FROM Bugs WHERE assigned_to = :assignedTo AND status = :status'; $stmt = $pdo->prepare($sql); $stmt->execute($params); return $stmt->fetchAll(PDO::FETCH_CLASS, Bug::class); } # " % #VHΫϥε͕ະఆٛ  ͜͜Ͱ σʔλϕʔε઀ଓΤϥʔ ˞ઃఆʹΑΔ
  12. public static function findAll($params) { global $CONF; $pdo = new

    PDO($CONF['dsn'], $CONF['usr'], $CONF['passwd'], [ PDO::ATTR_EMULATE_PREPARES => false ]); $sql = 'SELECT bug_id, summary, date_reported FROM Bugs WHERE assigned_to = :assignedTo AND status = :status'; $stmt = $pdo->prepare($sql); $stmt->execute($params); return $stmt->fetchAll(PDO::FETCH_CLASS, Bug::class); } ɹॲཧࣦഊͷݪҼʹͳΔՄೳੑ͕͋Δͷ͸Ͳͷߦ # " % ᶃ ᶄ ᶅ ᶆ ͑ͬɺ͜Μͳʹ͋Δͷ 
  13. ɹ͜ͷͳ͔Ͱ΋ಛʹखڧ͍ঢ়گ͸ͲΕ σʔλϕʔε઀ଓཱࣦ֬ഊ AVTSA AQBTTXEA౳Ωʔ໊͕มߋ͞Εͨ ςʔϒϧ໊΍ΧϥϜ໊͕୭͔ʹมߋ͞Εͨ QBSBNT͕OVMM QBSBNTͷΩʔ໊΍਺ͷෆҰக QBSBNTͷ஋͕จࣈྻʹม׵ෆೳ #VHΫϥε͕ະఆٛ ్தͰσʔλϕʔε઀ଓΤϥʔ

  14. ɹࢲݟͰ͸QBSBNTͷΩʔ໊΍਺ͷෆҰக public static function findAll($params) { global $CONF; $pdo =

    new PDO($CONF['dsn'], $CONF['usr'], $CONF['passwd'], [ PDO::ATTR_EMULATE_PREPARES => false ]); $sql = 'SELECT bug_id, summary, date_reported FROM Bugs WHERE assigned_to = :assignedTo AND status = :status'; $stmt = $pdo->prepare($sql); $stmt->execute($params); return $stmt->fetchAll(PDO::FETCH_CLASS, Bug::class); } QBSBNTͷΩʔ໊΍਺ͷෆҰக # " %
  15. $ php example.php PHP Warning: PDOStatement::execute(): SQLSTATE[HY093]: Invalid parameter number:

    parameter was not defined in example.php Array ( ) ɹΩʔ໊΍਺Λؒҧ࣮͑ͯߦ͢ΔͱͲ͏ͳΔ ཪͰͬͦ͜Γܯࠂ͕ग़Δ͚ͩͳͷ  ۭ഑ྻ͕ฦͬͯ͘Δͷ  ਖ਼ৗܥͱݟ෼͚͕͔ͭͳ͘ͳ͍  
  16. ෆ۩߹ͷൃݟ͕ ஗ΕΕ͹஗ΕΔ΄Ͳ ই͸ਂ͘ͳΔ IUUQTXXXBTURCPSHQSFTTSPPN*452#@$FSUJpDBUJPO@/FXT@@IUNM

  17. public static function findAll($params) { global $CONF; $pdo = new

    PDO($CONF['dsn'], $CONF['usr'], $CONF['passwd'], [ PDO::ATTR_EMULATE_PREPARES => false ]); $sql = 'SELECT bug_id, summary, date_reported FROM Bugs WHERE assigned_to = :assignedTo AND status = :status'; $stmt = $pdo->prepare($sql); $stmt->execute($params); return $stmt->fetchAll(PDO::FETCH_CLASS, Bug::class); } ɹॲཧࣦഊͷݪҼʹͳΔՄೳੑ͕͋Δͷ͸Ͳͷߦ # " % ᶃ ᶄ ᶅ ᶆ ݱ࣮ੈք΁Α͏ͦ͜
  18. lݡ໌ͳιϑτ΢ΣΞٕज़ऀʹ ͳΔͨΊͷୈҰา͸ɺಈ͘ϓϩ άϥϜΛॻ͘͜ͱͱਖ਼͍͠ϓϩ άϥϜΛద੾ʹ࡞੒͢Δ͜ͱͷ ҧ͍Λೝࣝ͢Δ͜ͱz Š."+BDLTPO 

  19. ɹݎ࿚ͳίʔυ͸Ҏ্͕ΤϥʔϋϯυϦϯά

  20. Agenda ୈ෦༧๷తϓϩάϥϛϯά ୈ෦߈ܸతϓϩάϥϛϯά ୈ෦ܖ໿ϓϩάϥϛϯά

  21. ɹࣦഊͷݪҼʹ͍ͭͯߟ͑࢝ΊΑ͏ ❔σʔλϕʔε઀ଓཱࣦ֬ഊ ❔AVTSA AQBTTXEA౳Ωʔ໊͕มߋ͞Εͨ ❔ςʔϒϧ໊΍ΧϥϜ໊͕୭͔ʹมߋ͞Εͨ ❔QBSBNT͕OVMM ❔QBSBNTͷΩʔ໊΍਺ͷෆҰக ❔QBSBNTͷ஋͕จࣈྻʹม׵ෆೳ ❔#VHΫϥε͕ະఆٛ ❔్தͰσʔλϕʔε઀ଓΤϥʔ

  22. σʔλϕʔε઀ଓཱࣦ֬ഊ AVTSA AQBTTXEA౳Ωʔ໊͕มߋ͞Εͨ ςʔϒϧ໊΍ΧϥϜ໊͕୭͔ʹมߋ͞Εͨ QBSBNT͕OVMM QBSBNTͷΩʔ໊΍਺ͷෆҰக QBSBNTͷ஋͕จࣈྻʹม׵ෆೳ #VHΫϥε͕ະఆٛ ్தͰσʔλϕʔε઀ଓΤϥʔ ɹࣦഊͷݪҼΛΧςΰϦ෼͚ͯ͠ΈΔ

  23. σʔλϕʔε઀ଓཱࣦ֬ഊ AVTSA AQBTTXEA౳Ωʔ໊͕มߋ͞Εͨ ςʔϒϧ໊΍ΧϥϜ໊͕୭͔ʹมߋ͞Εͨ QBSBNT͕OVMM QBSBNTͷΩʔ໊΍਺ͷෆҰக QBSBNTͷ஋͕จࣈྻʹม׵ෆೳ #VHΫϥε͕ະఆٛ ్தͰσʔλϕʔε઀ଓΤϥʔ ɹؒҧͬͨ࢖ΘΕํΛ͞Ε΍͍͢ɺͱ͍͏໰୊͕͋Γͦ͏

  24. ରॲ༧๷ ༧๷తϓϩάϥϛϯά

  25. w ʮ๷ޚతϓϩάϥϛϯάʯͱ͸ɺϓϩάϥϛϯάʹ ରͯ͠๷ޚతʹͳΔ͜ͱɺͭ·Γʮͦ͏ͳΔ͸ͣ ͩʯͱܾΊ͚ͭͳ͍͜ͱ w ๷ޚతϓϩάϥϛϯάͷࠜఈʹ͋Δͷ͸ɺϧʔνϯ ʹෆਖ਼ͳσʔλ͕౉͞Εͨͱ͖ʹɺͦΕ͕ଞͷϧʔ νϯͷ͍ͤͰ͋ͬͨͱͯ͠΋ɺඃ֐Λड͚ͳ͍Α͏ ʹ͢Δ͜ͱ w

    ͜ͷͨΊɺ w ֎෦ιʔε͔Βͷσʔλͷ஋Λ͢΂ͯ֬ೝ͢Δ w ϧʔνϯͷ͢΂ͯͷೖྗҾ਺ͷ஋Λ֬ೝ͢Δ w ෆਖ਼ͳೖྗΛॲཧ͢Δํ๏Λܾఆ͢Δ ๷ޚతϓϩάϥϛϯά
  26. ڱٛͷ ๷ޚతϓϩά ϥϛϯά΁ͷޡղ

  27. public static function findAll($params) { if (is_null($params)) { throw new

    InvalidArgumentException('params should not be null'); } if (!is_array($params)) { throw new InvalidArgumentException('params should be an array'); } if (count($params) !== 2) { throw new InvalidArgumentException('params should be have exact two items'); } if (!array_key_exists('assignedTo', $params) || !array_key_exists('status', $params)) { throw new InvalidArgumentException('params should have key `assignedTo` and `status` only'); } if (!is_int($params['assignedTo'])) { throw new InvalidArgumentException('params[`assignedTo`] should be an integer'); } if (!is_string($params['status'])) { throw new InvalidArgumentException('params[`status`] should be a string'); } if (!in_array($params['status'], ['OPEN', 'NEW', 'FIXED'], true)) { throw new InvalidArgumentException('params[`status`] should be in `OPEN`,`NEW`,`FIXED`'); } global $CONF; $pdo = new PDO($CONF['dsn'], $CONF['usr'], $CONF['passwd'], [ PDO::ATTR_EMULATE_PREPARES => false ]); ɹͨͩͻͨ͢ΒೖྗΛνΣοΫ͠Α͏ͱͨ͠Γ # " %
  28. global $CONF; $dsn = $CONF['dsn'] ?? $CONF['ds'] ?? $CONF['dataSource']; $user

    = $CONF['usr'] ?? $CONF['user']; $password = $CONF['passwd'] ?? $CONF['password']; $pdo = new PDO($dsn, $user, $password, [ PDO::ATTR_EMULATE_PREPARES => false ]); $sql = 'SELECT bug_id, summary, date_reported FROM Bugs WHERE assigned_to = :assignedTo AND status = :status'; $stmt = $pdo->prepare($sql); $safeParams = [ 'assignedTo' => $params['assignedTo'] ?? $params['assigned_to'], 'status' => $params['status'] ?? 'OPEN', ]; $stmt->execute($safeParams); $className = class_exists('Bug') ? 'Bug' : 'BugModel'; return $stmt->fetchAll(PDO::FETCH_CLASS, $className); ɹෆਖ਼ͳೖྗ͕͋ͬͯ΋ࣗ෼ͰͳΜͱ͔͠Α͏ͱͨ͠Γ # " %
  29. /** * 担当者, ステータスに合致する Bug を検索し、ヒットした全件を Bug オブジェクト の配列として返す。 *

    * @param array $params 格納した検索条件の連想配列。キー `assignedTo` にユーザID をintで, キー `status` にステータス文字列をstringで指定すること。キー、値それぞ れNULLは不可とする。 * @return Bug[] 検索結果を Bug オブジェクトにマッピングして返す。検索結果が0件 のときは空配列を返す。 */ public static function findAll($params) { global $CONF; $pdo = new PDO($CONF['dsn'], $CONF['usr'], $CONF['passwd'], [ PDO::ATTR_EMULATE_PREPARES => false ]); ɹυΩϡϝϯτͰؒҧ͍΍͢͞Λิ͓͏ͱͨ͠Γ # " %
  30. ๷ޚతϓϩάϥϛϯάͱ͸ ѱ͍ίʔυʹឺ૑ߣΛ͋ͯ Δ͜ͱͰ͸ͳ͍

  31. w ʮ๷ޚతϓϩάϥϛϯάʯͱ͸ɺ໰୊ൃੜΛ ࣄલʹ๷͝͏ͱ͍͏ίʔσΟϯάελΠϧ w Մಡੑͷߴ͍ίʔυͱద੾ͳ໋໊نଇ w શͯͷؔ਺ͷ໭Γ஋ΛνΣοΫ w σβΠϯύλʔϯͷ࠾༻ w

    ཁ͢Δʹɺྑࣝ͋Δ࣮ફͷੵΈॏͶͰ͋Δ w ๷ޚతϓϩάϥϛϯά͸ɺਖ਼͍͠ίʔυ࡞੒ ͷͨΊͷن཯ΛϓϩάϥϚ͕Ұ؏ͯ͠ద༻͢ ΔͨΊͷҰछͷίʔσΟϯάඪ४ ๷ޚతϓϩάϥϛϯά
  32. wྑ͍ΠϯλϑΣʔεͱ͸࣍ͷͭͷ ৚݅Λຬͨ͢ΠϯλϑΣʔε wਖ਼͘͠࢖༻͢Δํ͕ૢ࡞ϛεΛ ͢ΔΑΓ؆୯ wޡͬͨ࢖͍ํΛ͢Δ͜ͱ͕ࠔ೉ ͖ͷ͜ਖ਼͍͠࢖͍ํΛ؆୯ʹɺ ޡͬͨ࢖͍ํΛࠔ೉ʹ

  33. ܕͷ੍ݶ ܕએݴ

  34. lʮग़དྷͯ͸ͳΒ͵͜ͱΛې͡Δʯͷ Ͱ͸ͳ͘ɺ͸͡Ί͔Βʮग़དྷ͍͍ͯ͜ ͱ͚ͩΛग़དྷΔΑ͏ʹ͢Δʯͱߟ͑Δ ͷͰ͢z ͖ͷ͜+ ݟ஌Β͵ਓͱ΋͏·͘΍Δʹ͸

  35. public static function findAll(int $assignedTo, string $status) { if (is_null($params))

    { throw new InvalidArgumentException('params should not be null'); } if (!is_array($params)) { throw new InvalidArgumentException('params should be an array'); } if (count($params) !== 2) { throw new InvalidArgumentException('params should be have exact two items'); } if (!array_key_exists('assignedTo', $params) || !array_key_exists('status', $params)) { throw new InvalidArgumentException('params should have key `assignedTo` and `status` only'); } if (!is_int($params['assignedTo'])) { throw new InvalidArgumentException('params[`assignedTo`] should be an integer'); } if (!is_string($params['status'])) { throw new InvalidArgumentException('params[`status`] should be a string'); } if (!in_array($params['status'], ['OPEN', 'NEW', 'FIXED'], true)) { throw new InvalidArgumentException('params[`status`] should be in `OPEN`,`NEW`,`FIXED`'); } ɹܕએݴʹΑͬͯʮग़དྷ͍͍ͯ͜ͱ͚ͩΛग़དྷΔʯΑ͏ʹ 1 ) 1 
  36. public static function findAll(int $assignedTo, string $status) { if (!in_array($status,

    ['OPEN', 'NEW', 'FIXED'], true)) { throw new InvalidArgumentException('params[`status`] should be in `OPEN`,`NEW`,`FIXED`'); } global $CONF; $pdo = new PDO($CONF['dsn'], $CONF['usr'], $CONF['passwd'], [ PDO::ATTR_EMULATE_PREPARES => false ]); $sql = 'SELECT bug_id, summary, date_reported FROM Bugs WHERE assigned_to = :assignedTo AND status = :status'; $stmt = $pdo->prepare($sql); $stmt->bindValue(':assignedTo', $assignedTo, PDO::PARAM_INT); $stmt->bindValue(':status', $status, PDO::PARAM_STR); $stmt->execute(); return $stmt->fetchAll(PDO::FETCH_CLASS, Bug::class); } ɹ૝ఆ͠ͳ͚Ε͹ͳΒͳ͍ঢ়گ͕ݮͬͨ 1 ) 1  注: さらに堅くしたい場合は 呼び出し側ファイルで厳密な型チェックを有効にする declare(strict_types=1);
  37. ஋ͷ੍ݶ &OVN

  38. ͖ͷ͜ ؔ਺ͷʮαΠζʯΛখ͘͢͞Δ wݴޠ૊ΈࠐΈͷܕ JOU TUSJOH౳ Λ ࢖͏ͱɺऔΓಘΔ஋ͷ૊Έ߹Θ͕ͤ ๲େʹͳΔ w໰୊ྖҬͷ஌ࣝΛ׆༻ͯ͠ݻ༗ͷܕ Λ࡞Δ͜ͱͰɺऔΓಘΔ૊Έ߹Θͤ

    Λେ෯ʹݮΒͤΔ
  39. IUUQRJJUBDPN)JSBLVJUFNTFCEDBBGF

  40. abstract class Enum { private $scalar; public function __construct($value) {

    $ref = new ReflectionObject($this); $constants = $ref->getConstants(); if (!in_array($value, $constants, true)) { throw new InvalidArgumentException("value [{$value}] is not defined"); } $this->scalar = $value; } final public function value() { return $this->scalar; } final public function __toString() { return (string)$this->scalar; } } ɹ)JSBLV͞Μͷ&OVN࣮૷Λ গ͠ΞϨϯδͯ͠ ࢖ͬͯΈΔ
  41. final class Status extends Enum { const OPEN = 'OPEN';

    const NEW = 'NEW'; const FIXED = 'FIXED'; } $status = new Status(Status::OPEN); $status = new Status('OPEN'); // "InvalidArgumentException: value [HOGE] is not defined" $status = new Status('HOGE'); ɹ͋Β͔͡Ίఆٛ͞Εͨ஋͚ͩΛΠϯελϯεԽͰ͖Δ
  42. public static function findAll(int $assignedTo, Status $status) { if (!in_array($status,

    ['OPEN', 'NEW', 'FIXED'], true)) { throw new InvalidArgumentException('params[`status`] should be in `OPEN`,`NEW`,`FIXED`'); } global $CONF; $pdo = new PDO($CONF['dsn'], $CONF['usr'], $CONF['passwd'], [ PDO::ATTR_EMULATE_PREPARES => false ]); $sql = 'SELECT bug_id, summary, date_reported FROM Bugs WHERE assigned_to = :assignedTo AND status = :status'; $stmt = $pdo->prepare($sql); $stmt->bindValue(':assignedTo', $assignedTo, PDO::PARAM_INT); $stmt->bindValue(':status', $status->value(), PDO::PARAM_STR); $stmt->execute(); return $stmt->fetchAll(PDO::FETCH_CLASS, Bug::class); } ɹ૝ఆ͠ͳ͚Ε͹ͳΒͳ͍ঢ়گ͕͞Βʹݮͬͨ
  43. σʔλϕʔε઀ଓཱࣦ֬ഊ AVTSA AQBTTXEA౳Ωʔ໊͕มߋ͞Εͨ ςʔϒϧ໊΍ΧϥϜ໊͕୭͔ʹมߋ͞Εͨ QBSBNT͕OVMM QBSBNTͷΩʔ໊΍਺ͷෆҰக QBSBNTͷ஋͕จࣈྻʹม׵ෆೳ #VHΫϥε͕ະఆٛ ్தͰσʔλϕʔε઀ଓΤϥʔ ɹޡΓ΍͍͢ΠϯλʔϑΣΠεʹىҼ͢ΔॲཧࣦഊΛ๾໓

    ✔ ✔ ✔
  44. σʔλϕʔε઀ଓཱࣦ֬ഊ AVTSA AQBTTXEA౳Ωʔ໊͕มߋ͞Εͨ ςʔϒϧ໊΍ΧϥϜ໊͕୭͔ʹมߋ͞Εͨ QBSBNT͕OVMM QBSBNTͷΩʔ໊΍਺ͷෆҰக QBSBNTͷ஋͕จࣈྻʹม׵ෆೳ #VHΫϥε͕ະఆٛ ్தͰσʔλϕʔε઀ଓΤϥʔ ɹ࣍ͷ૬ख͸ɺ஌Γ͗͢ɺ੹຿ͷଟ͗͢ʹىҼ͢Δॲཧࣦഊ

  45. ஌Γ͗͢ͳ͍ ΍Γ͗͢ͳ͍ ੹຿ͷ࠶഑ஔ

  46. class BugRepository { private $pdo; public function __construct(PDO $pdo) {

    $this->pdo = $pdo; } // 以下省略 } // 設定者 (DI コンテナ等) $pdo = new PDO($CONF['dsn'], $CONF['usr'], $CONF['passwd'], [ PDO::ATTR_EMULATE_PREPARES => false, ]); $repo = new BugRepository($pdo); // 利用者 print_r($repo->findAll(12, new Status(Status::OPEN))); ɹ1%0ੜ੒ͱઃఆͷ੹຿Λ֎෦ʹग़͠ɺίϯετϥΫλͰड͚औΔ
  47. σʔλϕʔε઀ଓཱࣦ֬ഊ AVTSA AQBTTXEA౳Ωʔ໊͕มߋ͞Εͨ ςʔϒϧ໊΍ΧϥϜ໊͕୭͔ʹมߋ͞Εͨ QBSBNT͕OVMM QBSBNTͷΩʔ໊΍਺ͷෆҰக QBSBNTͷ஋͕จࣈྻʹม׵ෆೳ #VHΫϥε͕ະఆٛ ్தͰσʔλϕʔε઀ଓΤϥʔ ɹ஌Γ͗͢ɺ੹຿ͷଟ͗͢ʹىҼ͢ΔॲཧࣦഊΛ๾໓

    ✔ ✔
  48. public static function findAll($params) { if (is_null($params)) { throw new

    InvalidArgumentException('params should not be null'); } if (!is_array($params)) { throw new InvalidArgumentException('params should be an array'); } if (count($params) !== 2) { throw new InvalidArgumentException('params should be have exact two items'); } if (!array_key_exists('assignedTo', $params) || !array_key_exists('status', $params)) { throw new InvalidArgumentException('params should have key `assignedTo` and `status` only'); } if (!is_int($params['assignedTo'])) { throw new InvalidArgumentException('params[`assignedTo`] should be an integer'); } if (!is_string($params['status'])) { throw new InvalidArgumentException('params[`status`] should be a string'); } if (!in_array($params['status'], ['OPEN', 'NEW', 'FIXED'], true)) { throw new InvalidArgumentException('params[`status`] should be in `OPEN`,`NEW`,`FIXED`'); } global $CONF; if (!isset($CONF['dsn'])) { throw new LogicException('config key `dsn` not found'); } if (!isset($CONF['usr'])) { throw new LogicException('config key `usr` not found'); } if (!isset($CONF['passwd'])) { throw new LogicException('config key `passwd` not found'); } $pdo = new PDO($CONF['dsn'], $CONF['usr'], $CONF['passwd'], [ PDO::ATTR_EMULATE_PREPARES => false ]); $sql = 'SELECT bug_id, summary, date_reported FROM Bugs WHERE assigned_to = :assignedTo AND status = :status'; $stmt = $pdo->prepare($sql); $stmt->execute($params); if (!class_exists('Bug')) { throw new LogicException('class `Bug` does not exist'); } return $stmt->fetchAll(PDO::FETCH_CLASS, Bug::class); } public function __construct(PDO $pdo) { $this->pdo = $pdo; } public function findAll(int $assignedTo, Status $status) { $sql = 'SELECT bug_id, summary, date_reported FROM Bugs WHERE assigned_to = :assignedTo AND status = :status'; $stmt = $this->pdo->prepare($sql); $stmt->bindValue(':assignedTo', $assignedTo, PDO::PARAM_INT); $stmt->bindValue(':status', $status->value(), PDO::PARAM_STR); $stmt->execute(); return $stmt->fetchAll(PDO::FETCH_CLASS, Bug::class); } ୈ෦·ͱΊ༧๷ʹউΔ๷ޚͳ͠
  49. Agenda ୈ෦༧๷తϓϩάϥϛϯά ୈ෦߈ܸతϓϩάϥϛϯά ୈ෦ܖ໿ϓϩάϥϛϯά

  50. ςʔϒϧ໊΍ΧϥϜ໊͕୭͔ʹมߋ͞Εͨ #VHΫϥε͕ະఆٛ ్தͰσʔλϕʔε઀ଓΤϥʔ ɹʮ్தͰσʔλϕʔε઀ଓΤϥʔʯʹऔΓ૊Ή

  51. GBJMGBTU ߈ܸతϓϩάϥϛϯά

  52. w ίʔυதʹʮ͋Γಘͳ͍ʯͱࢥΘΕΔԿ͔ ͕ൃੜͨ͠৔߹ɺͦͷ࣌఺ͰϓϩάϥϜ͸ ΋͸΍࣮ߦՄೳͳ΋ͷͱ͸ͳ͍ͬͯͳ͍ w ԿΒ͔ͷ͍͕ٙ͋ΔͷͰ͋Ε͹ɺͲͷΑ͏ ͳ৔߹Ͱ΋଎΍͔ʹఀࢭͤ͞Δ΂͖ɻ௨ৗ ͷ৔߹ɺো֐Λ๊͑ͯத్൒୺ʹಈ͍͍ͯ ΔϓϩάϥϜΑΓ΋ࢮΜͩϓϩάϥϜͷ΄ ͏͕μϝʔδ͸গͳ͍

    ώϯτૣΊʹΫϥογϡͤ͞Δ͜ͱ
  53. IUUQTXXXBTURCPSHQSFTTSPPN*452#@$FSUJpDBUJPO@/FXT@@IUNM ো֐Λ๊͑ͯ த్൒୺ʹಈ͍͍ͯΔϓϩάϥϜΑΓ΋ ࢮΜͩϓϩάϥϜͷ΄͏͕ μϝʔδ͸গͳ͍

  54. ͦΜͳʹؾָʹ γεςϜΛམͱͯ͠ ͍͍ͷ 

  55. w ࠷దͳΤϥʔॲཧ͸Τϥʔ͕ൃੜͨ͠ιϑτ΢ΣΞ ͷछྨʹΑΓҟͳΔ w ਖ਼౰ੑͱ͸ɺෆਖ਼֬ͳ݁ՌΛܾͯ͠ฦ͞ͳ͍͜ͱΛ ҙຯ͢Δɻෆਖ਼֬ͳ݁ՌΛฦ͘͢Β͍ͳΒɺԿ΋ฦ ͞ͳ͍ํ͕·͠Ͱ͋Δ w ݎ࿚ੑͱ͸ɺιϑτ΢ΣΞͷ࣮ߦΛܧଓͰ͖ΔΑ͏ ʹखΛਚ͘͢͜ͱͰ͋ΔɻͦΕʹΑͬͯෆਖ਼͕֬݁

    Ռ͕΋ͨΒ͞ΕΔ͜ͱ͕͋ͬͯ΋͔·Θͳ͍ w ҆શੑ ΍ਖ਼֬ੑ Λॏࢹ͢ΔΞϓϦέʔγϣϯͰ ͸ɺݎ࿚ੑΑΓ΋ਖ਼౰ੑ͕༏ઌ͞ΕΔ܏޲ʹ͋Δ w ίϯγϡʔϚΞϓϦέʔγϣϯͰ͸ɺਖ਼౰ੑΑΓ΋ ݎ࿚ੑ͕༏ઌ͞ΕΔ܏޲ʹ͋Δ ਖ਼౰ੑͱݎ࿚ੑ
  56. ݸʑͷΫϥε͸ਖ਼౰ੑΛॏࢹ͠ɺ ݎ࿚ੑ͸ΞʔΩςΫνϟϑϨʔϜϫʔΫ౳Ͱ อূ͢Δͷ͕Φεεϝ ྫݸʑͷΫϥε͸GBJMGBTUݪଇͰॻ͖ɺ8FC ϑϨʔϜϫʔΫ΍άϩʔόϧϋϯυϥ͕Ωϟον ͯ͠Τϥʔը໘౳Λग़͢੹຿Λෛ͏ ɹϛΫϩͰ͸ਖ਼౰ੑΛॏࢹ͠ɺϚΫϩͰ͸ݎ࿚ੑΛॏࢹ͢Δ

  57. ʮ͔΋͠Εͳ͍ʯ ྫ֎తঢ়گʹରॲ ͢Δ

  58. ͖ͷ͜ ΤϥʔΛແࢹ͢Δͳ wΤϥʔΛແࢹͯ͠΋Կ΋ྑ͍͜ͱ͸ແ͍ wෆ҆ఆͳίʔυ wηΩϡϦςΟ্໰୊ͷ͋Δίʔυ wශऑͳߏ଄ͱΠϯλʔϑΣΠε wͲ͏͢Δ  w໭Γ஋Λ࢖͏ wྫ֎Λ࢖͏

  59. public function findAll(int $assignedTo, Status $status) { $sql = 'SELECT

    bug_id, summary, date_reported FROM Bugs WHERE assigned_to = :assignedTo AND status = :status'; if (($stmt = $this->pdo->prepare($sql)) !== false) { if ($stmt->bindValue(':assignedTo', $assignedTo, PDO::PARAM_INT) !== false) { if ($stmt->bindValue(':status', $status->value(), PDO::PARAM_STR) !== false) { if ($stmt->execute() !== false) { if (($bugs = $stmt->fetchAll(PDO::FETCH_CLASS, Bug::class)) !== false) { return $bugs; } } } } } return false; } ɹ1%0Τϥʔ࣌ͷ໭Γ஋ GBMTF ΛνΣοΫ͢Δ # " % ೾ಈݓ NJYFEฦ͠
  60. public function findAll(int $assignedTo, Status $status) { $sql = 'SELECT

    bug_id, summary, date_reported FROM Bugs WHERE assigned_to = :assignedTo AND status = :status'; if (($stmt = $this->pdo->prepare($sql)) === false) { $error = $this->pdo->errorInfo(); report_error('prepare: ' . $error[2]); return false; } if ($stmt->bindValue(':assignedTo', $assignedTo, PDO::PARAM_INT) === false) { $error = $stmt->errorInfo(); report_error('bindValue: ' . $error[2]); return false; } if ($stmt->bindValue(':status', $status->value(), PDO::PARAM_STR) === false) { $error = $stmt->errorInfo(); report_error('bindValue: ' . $error[2]); return false; } if ($stmt->execute() === false) { $error = $stmt->errorInfo(); report_error('execute: ' . $error[2]); return false; } if (($bugs = $stmt->fetchAll(PDO::FETCH_CLASS, Bug::class)) === false) { $error = $stmt->errorInfo(); report_error('fetchAll: ' . $error[2]); return false; } return $bugs; } ɹ໭Γ஋ GBMTF ΛνΣοΫͯ͠ૣظϦλʔϯ # " % ஫SFQPSU@FSSPS͸ϩάʹग़ࣗ͢࡞ؔ਺ NJYFEฦ͠
  61. ໭Γ஋ͷऑ఺ ໭Γ஋͸ ɹίʔυ͕ංେԽ͕ͪ͠ ɹແࢹ͞Ε΍͍͢ ɹͨͱ͑ॏେͳ໰୊͕જΜͰ͍ͯ ΋ɺ໭Γ஋͚ͩͰ͸఻ΘΓʹ͍͘ ࣮ࡍ$ݴޠͷؔ਺ͷ໭Γ஋ͷதʹ͸ʮແࢹ͢Δͷ͕ී ௨ʯͱ͞Ε͍ͯΔ΋ͷ͑͋͞Δ

  62. ෆ۩߹ͷൃݟ͕ ஗ΕΕ͹஗ΕΔ΄Ͳ ই͸ਂ͘ͳΔ IUUQTXXXBTURCPSHQSFTTSPPN*452#@$FSUJpDBUJPO@/FXT@@IUNM

  63. PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION それだ!! 1%0Λྫ֎Ϟʔυʹ͠Α͏ IUUQQIQOFUNBOVBMKBQEPFSSPSIBOEMJOHQIQ

  64. public function findAll(int $assignedTo, Status $status) { $sql = 'SELECT

    bug_id, summary, date_reported FROM Bugs WHERE assigned_to = :assignedTo AND status = :status'; $stmt = $this->pdo->prepare($sql); $stmt->bindValue(':assignedTo', $assignedTo, PDO::PARAM_INT); $stmt->bindValue(':status', $status->value(), PDO::PARAM_STR); $stmt->execute(); return $stmt->fetchAll(PDO::FETCH_CLASS, Bug::class); } // 設定者 $pdo = new PDO($CONF['dsn'], $CONF['usr'], $CONF['passwd'], [ PDO::ATTR_EMULATE_PREPARES => false, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, ]); $repo = new BugRepository($pdo); ɹGBMTFͷ୅ΘΓʹ1%0&YDFQUJPO͕ൃੜ͢ΔΑ͏ʹͳΔ $ php example.php PHP Fatal error: Uncaught PDOException: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'date_reported' in 'field list' in /path/ to/example.php:63
  65. wྫ֎ͷ࠷େͷར఺͸ɺແࢹͰ͖ͳ͍ ํ๏ͰΤϥʔঢ়ଶΛ஌ΒͤΔ͜ͱͰ ͋Δ ΦϒδΣΫτࢦ޲ೖ໳ୈ൛  wྫ֎ΛނҙʹѲΓͭͿ͢͜ͱ͸Մೳ ͕ͩɺͦ͏͍͏ίʔυ͕ॻ͔Ε͍ͯ Δͱ͖͸ɺॻ͖खͷ࢟੎ʹ໰୊͕͋ Δͱ͙͢ʹΘ͔Δ ͖ͷ͜

    ྫ֎ͷར఺
  66. ςʔϒϧ໊΍ΧϥϜ໊͕୭͔ʹมߋ͞Εͨ #VHΫϥε͕ະఆٛ ్தͰσʔλϕʔε઀ଓΤϥʔ ✔ ɹݱࡏͷ৺഑ࣄϦετ ͕ͩɺͪΐͬͱ଴ͬͯ΄͍͠

  67. ςʔϒϧ໊΍ΧϥϜ໊͕୭͔ʹมߋ͞Εͨ #VHΫϥε͕ະఆٛ ్தͰσʔλϕʔε઀ଓΤϥʔ ΋͠΋1%0͕ྫ֎ϞʔυͰͳ͔ͬͨΒ ɹ҉໧ͷલఏ͕ՃΘΓɺ৺഑ࣄ͕૿͍͑ͯͳ͍͔ ✔

  68. ҉໧ͷલఏΛ໌ࣔ͠ όάΛ͋ͿΓग़͢ ද໌ϓϩάϥϛϯά

  69. ʮى͜Δ͸͕ͣͳ͍ʯͱࢥͬͯ ͍Δ͜ͱ͕͋Ε͹ɺͦΕΛνΣο Ϋ͢ΔίʔυΛ௥Ճͯͩ͘͠͞ ͍ɻද໌ BTTFSUJPO Λ༻͍Δͷ ͕࠷΋؆୯ͳํ๏Ͱ͢ ώϯτ΋͠ى͜Γಘͳ͍ͱ͍͏ͷͰ͋Ε͹ɺ ද໌Λ༻͍ͯͦΕΛอূ͢Δ͜ͱ

  70. 1)1ͷBTTFSU 1 ) 1  IUUQQIQOFUNBOVBMKBGVODUJPOBTTFSUQIQ

  71. public function findAll(int $assignedTo, Status $status) { assert($this->pdo->getAttribute(PDO::ATTR_ERRMODE) === PDO::ERRMODE_EXCEPTION);

    $sql = 'SELECT bug_id, summary, date_reported FROM Bugs WHERE assigned_to = :assignedTo AND status = :status'; $stmt = $this->pdo->prepare($sql); ɹൃੜͨ͠҉໧ͷલఏΛBTTFSUʹධՁࣜͰॻ͖ɺ໌ࣔ͢Δ あらたに PDO::ERRMODE_EXCEPTION に 依存するようになったことを assert で明示する
  72. $ php example.php PHP Warning: assert(): assert($this->pdo->getAttribute(PDO::ATTR_ERRMODE) === PDO::ERRMODE_EXCEPTION) failed

    in /path/to/example.php on line 59 PHP Fatal error: Uncaught Error: Call to a member function bindValue() on boolean in /path/to/example.php:63 ɹͬͦ͘͞ද໌ೖΓͷίʔυΛ࣮ߦͯ͠ΈΔ ධՁ͕ࣜग़ͯΘ͔Γ΍͍͢ Ͱ΋ܯࠂ͕ग़Δ͚ͩͰɺམͪͳ͍  མͪͳ͍ͷͰͦͷઌͰผͷΤϥʔʹͳͬͨ  1 ) 1 
  73. 1)1ͷBTTFSUͷઃఆ 1 ) 1  PHP5 との互換性を保つためデフォルトでは警告になっている。 つまり php.ini で

    assert.exception = 1 にすべし IUUQQIQOFUNBOVBMKBGVODUJPOBTTFSUQIQ
  74. $ php example.php PHP Fatal error: Uncaught AssertionError: assert($this->pdo->getAttribute(PDO::ATTR_ERRMODE) ===

    PDO::ERRMODE_EXCEPTION) in /path/to/example.php:59 Stack trace: #0 /path/to/example.php(59): assert(false, 'assert($this->p...') #1 /path/to/example.php(75): BugRepository->findAll(12, Object(Status)) #2 {main} thrown in /path/to/example.php on line 59 ɹBTTFSUFYDFQUJPOʹͯ͠࠶࣮ߦ ͖ͪΜͱද໌ҧ൓ͰམͪΔ Α͏ʹͳͬͨ 1 ) 1 
  75. w ද໌͸ίϛϡχέʔγϣϯͱσόοάͷπʔϧͱ ͯ͠ಇ͘ w ίϛϡχέʔγϣϯͷ؍఺Ͱ͸ɺද໌Λॻ͘͜ͱ ʹΑͬͯɺͦͷίʔυΛॻ͍ͨͱ͖ͷલఏΛίʔ υͷಡΈख͕ཧղ͠΍͘͢ͳΔ w σόοάͷ؍఺Ͱ͸ɺόάΛͦͷݪҼʹ͍ۙͱ͜ ΖͰൃݟ͠΍͘͢ͳΔ

    w ςετίʔυΛॻ͍ͯ͋Ε͹ɺσόοάͷࢧԉ͸ ͞΄ͲॏཁͰ͸ͳ͍͕ɺͦΕͰ΋ίϛϡχέʔ γϣϯͷ؍఺ʹ͓͚Δද໌ͷՁ஋͸ɺґવͱͯ͠ ༗ޮ ද໌ͷϝϦοτ
  76. ྫ֎ͱද໌ͷ࢖͍෼͚ w ຊདྷͷΤϥʔॲཧʹද໌Λ࢖ͬͯ͸͍ ͚·ͤΜɻද໌͸ى͜Γಘͳ͍͜ͱΛ νΣοΫ͢ΔͨΊͷ΋ͷͰ͢ ৽૷൛ ୡਓϓϩάϥϚʔ  w ൃੜ͕༧૝͞ΕΔঢ়گʹ͸Τϥʔॲཧ

    ίʔυΛ࢖༻͠ɺൃੜͯ͠͸ͳΒͳ͍ ঢ়گʹ͸ΞαʔγϣϯΛ࢖༻͢Δ $0%&$0.1-&5&ୈ൛
  77. w͋·Γʹ΋๷ޚతͳϓϩάϥϛϯ ά΋ɺͦΕ͸ͦΕͰ໰୊ wҾ਺Λߟ͑ΒΕΔݶΓͷ৔ॴͰ ߟ͑ΒΕΔݶΓͷํ๏ͰνΣο Ϋ͢Ε͹ɺϓϩάϥϜ͸ංେԽ ͠௿଎ʹͳΔ BTTFSUJPOΛೖΕ͗͢Δͱ ௿଎ʹͳΔͷͰ͸ʁ ʮ๷ޚతϓϩάϥϛϯάʹର͢Δ๷ޚʯΑΓ

  78. ͦ͜Ͱ1)1Ͱ͢Α 1 ) 1  php.ini の zend.assertions で表明のオン/オフを制御できる IUUQQIQOFUNBOVBMKBGVODUJPOBTTFSUQIQ

  79. ɹ[FOEBTTFSUJPOT ද໌Φϯ 1 ) 1  public function findAll(int $assignedTo,

    Status $status) { assert($this->pdo->getAttribute(PDO::ATTR_ERRMODE) === PDO::ERRMODE_EXCEPTION); $sql = 'SELECT bug_id, summary, date_reported FROM Bugs WHERE assigned_to = :assignedTo AND status = :status'; $stmt = $this->pdo->prepare($sql);
  80. public function findAll(int $assignedTo, Status $status) { assert($this->pdo->getAttribute(PDO::ATTR_ERRMODE) === PDO::ERRMODE_EXCEPTION);

    $sql = 'SELECT bug_id, summary, date_reported FROM Bugs WHERE assigned_to = :assignedTo AND status = :status'; $stmt = $this->pdo->prepare($sql); ɹ[FOEBTTFSUJPOT ද໌Φϑ 1 ) 1  php.ini に zend.assertions = -1 と設定すれば表明を除去できる
  81. ද໌ʹҾ͖౉͢৚݅ʹ͸෭࡞༻͕ ͋ͬͯ͸͍͚·ͤΜɻίϯύΠϧ࣌ʹ ද໌͕Φϑʹ͞ΕΔ৔߹΋͋Δͱ͍ ͏఺Λ๨Εͯ͸͍͚·ͤΜɻ ͭ·ΓBTTFSUதʹ͸࣮ߦʹඞཁͳ ίʔυΛهड़ͯ͠͸͍͚ͳ͍ͷͰ͢ ʮώϯτ΋͠ى͜Γಘͳ͍ͱ͍͏ͷͰ͋Ε͹ɺද໌Λ༻͍ͯͦΕΛอূ͢Δ͜ͱʯΑΓ ɹΦϑʹ͞ΕΔ͜ͱΛҙࣝͯ͠ॻ͘ 副作用の例: assert(end($users));

  82. w Ξαʔγϣϯ͸ɺQVCMJDϝιου಺ͷҾ਺νΣοΫ ʹ࢖༻͠ͳ͍Ͱ͍ͩ͘͞ w Ҿ਺ͷνΣοΫ͸௨ৗɺϝιουͷ࢓༷ ·ͨ͸ن໿ ͷҰ෦ʹͳ͓ͬͯΓɺΞαʔγϣϯͷ༗ޮແޮʹ͔ ͔ΘΒͣɺ͜ͷ࢓༷ʹ४ڌ͢Δඞཁ͕͋Γ·͢ɻ w ΞϓϦέʔγϣϯͷਖ਼͍͠ಈ࡞ʹඞཁͳॲཧΛ࣮ߦ

    ͢ΔͨΊʹΞαʔγϣϯΛ࢖༻͠ͳ͍Ͱ͍ͩ͘͞ IUUQTEPDTPSBDMFDPNKBWBTFKQEPDTUFDIOPUFTHVJEFTMBOHVBHFBTTFSUIUNM ʮΞαʔγϣϯΛ࢖༻ͨ͠ϓϩάϥϛϯάʯΑΓ ɹඞਢͷҾ਺νΣοΫ΍όϦσʔγϣϯʹ࢖Θͳ͍ +BWB
  83. IUUQTXXXBTURCPSHQSFTTSPPN*452#@$FSUJpDBUJPO@/FXT@@IUNM ୈ෦·ͱΊlGBJMGBTUz ো֐Λ๊͑ͯ த్൒୺ʹಈ͍͍ͯΔϓϩάϥϜΑΓ΋ ࢮΜͩϓϩάϥϜͷ΄͏͕ μϝʔδ͸গͳ͍

  84. ςʔϒϧ໊΍ΧϥϜ໊͕୭͔ʹมߋ͞Εͨ #VHΫϥε͕ະఆٛ ్தͰσʔλϕʔε઀ଓΤϥʔ ΋͠΋1%0͕ྫ֎ϞʔυͰͳ͔ͬͨΒ ɹݱࡏͷ৺഑ࣄϦετ ✔ ✔

  85. Agenda ୈ෦༧๷తϓϩάϥϛϯά ୈ෦߈ܸతϓϩάϥϛϯά ୈ෦ܖ໿ϓϩάϥϛϯά

  86. ͩΕͷ੹຿͔ ϋοΩϦͤ͞Δ ܖ໿ʹΑΔઃܭ

  87. ܖ໿ʹΑΔઃܭ

  88. wܖ໿ʹΑΔઃܭͱ͸ɺιϑτ΢ΣΞ Ϟδϡʔϧͷݖརͱ੹೚ΛจॻԽʢͦ ͯ͠ঝ୚ʣ͠ɺϓϩάϥϜͷਖ਼͠͞ Λอূ͢ΔͨΊͷ؆͔ܿͭύϫϑϧ ͳٕ๏Ͱ͢ wͰ͸ɺਖ਼͍͠ϓϩάϥϜͱ͸ҰମԿ Ͱ͠ΐ͏͔ʁ͜Ε͸ɺཁٻ͞Εͨ͜ ͱҎ্ͷ͜ͱ΋ɺͦΕҎԼͷ͜ͱ΋ ߦΘͳ͍ͱ͍͏΋ͷͰ͢ ώϯτܖ໿Λ༻͍ͯઃܭΛߦ͏͜ͱ

  89. \1^"\2^ ਖ਼͠͞ͷެࣜ )PBSF5SJQMF ࣄલ৚݅1͕੒Γཱͭͱ͖ʹɺϓϩάϥϜ"Λ࣮ߦ͢ Δͱͦͷ࣮ߦޙʹ͸ඞͣࣄޙ৚݅2͕੒ΓཱͭͳΒ ͹ɺϓϩάϥϜ"͸ɺࣄલ৚݅1ͱࣄޙ৚݅2ͱʹ ؔͯ͠෦෼తʹਖ਼౰ʢQBSUJBMMZDPSSFDUʣͰ͋Δ

  90. w΋ͦͪ͠Β͕ࣄલ৚݅Λຬͨͨ͠ঢ় ଶͰࢲΛݺͿͱ໿ଋͯ͠Լ͞ΔͳΒ ͹ɺ͓ฦ͠ʹࣄޙ৚݅Λຬͨ͢ঢ়ଶ Λ࠷ऴతʹ࣮ݱ͢Δ͜ͱΛ͓໿ଋ͠ ·͢ ܖ໿ʹΑΔઃܭ %FTJHOCZ$POUSBDU %C$

  91. ੒ޭࣦഊόάྫ֎ IUUQRJJUBDPN,PLVEPSJJUFNTBDGBC

  92. Throwable ├── Error │ ├── ArithmeticError │ │ └── DivisionByZeroError

    │ ├── AssertionError │ ├── ParseError │ └── TypeError └── Exception ├── ErrorException ├── LogicException │ ├── BadFunctionCallException │ │ └── BadMethodCallException │ ├── DomainException │ ├── InvalidArgumentException │ ├── LengthException │ └── OutOfRangeException └── RuntimeException ├── OutOfBoundsException ├── OverflowException ├── PDOException ├── RangeException ├── UnderflowException └── UnexpectedValueException 1 ) 1  3VOUJNF&YDFQUJPOܥ ྫ֎ -PHJD&YDFQUJPOܥόά &SSPSܥόά
  93. w࣮ߦ࣌ͷද໌ҧ൓ ΍ɺόάΛࣔͨ͢Ί ͷྫ֎ ͸ɺͦͷιϑτ΢ΣΞʹόά͕ ͋ΔূڌͰ͋Δ wࣄલ৚݅ҧ൓͸ݺͼग़͠ଆʹόά͕ ͋ΔূڌͰ͋Δ wࣄޙ৚݅ҧ൓͸ڙڅऀଆʹόά͕͋ ΔূڌͰ͋Δ ܖ໿ʹΑΔઃܭ

    %FTJHOCZ$POUSBDU %C$
  94. ɹ#VHΫϥε͕ະఆٛͷঢ়گʹ͸Ͳ͏උ͑Δ $ php example.php PHP Fatal error: Class 'Bug' not

    found in /path/to/example.php on line 85 ౴͑ͳʹ΋͠ͳ͍ɻ ͜Ε͸ྫ֎తঢ়گͰ͸ͳ͘ʢจࣈ௨ΓʣόάͰ ͋ΓɺϓϩάϥϛϯάϛεͳͷͰɺΤϥʔϋϯ υϦϯάͯ͠͸ͳΒͳ͍ɻͳʹ΋ͤͣɺ଎΍͔ ʹམͱ͢ɻGBJMGBTU͕ॏཁɻ
  95. ίϯετϥΫλͷ ܖ໿

  96. /** * 検索処理に使用する PDO インスタンスを渡し、バグリポジトリを初期化する。 * * @param PDO $pdo

    PDO インスタンス。 PDO::ATTR_ERRMODE が PDO::ERRMODE_EXCEPTION に 設定されていること * @throws InvalidArgumentException PDO::ATTR_ERRMODE が適切に設定されていない場合 */ public function __construct(PDO $pdo) { if ($pdo->getAttribute(PDO::ATTR_ERRMODE) !== PDO::ERRMODE_EXCEPTION) { throw new InvalidArgumentException('requires PDO::ERRMODE_EXCEPTION'); } $this->pdo = $pdo; } ɹίϯετϥΫλͷࣄલ৚݅Λදݱ͢Δ
  97. pOE"MMϝιου ͷܖ໿

  98. /** * 指定された担当者 ID およびステータスに合致する Bug を検索し、ヒットした全件を Bug オブジェクトの配列として返す。 *

    * @param int $assignedTo 担当者ID * @param Status $status ステータス * @return Bug[] 条件に合致した Bug オブジェクトの配列を返す。検索に合致するものがな い場合は空配列を返す * @throws LogicException カラム名違いや文法エラー等SQLのミスが存在する場合 * @throws PDOException データベースとのやりとりに何らかの障害が発生した場合 */ public function findAll(int $assignedTo, Status $status): array { assert($this->pdo->getAttribute(PDO::ATTR_ERRMODE) === PDO::ERRMODE_EXCEPTION); $sql = 'SELECT bug_id, summary, date_reported FROM Bugs WHERE assigned_to = :assignedTo AND status = :status'; try { $stmt = $this->pdo->prepare($sql); $stmt->bindValue(':assignedTo', $assignedTo, PDO::PARAM_INT); $stmt->bindValue(':status', $status->value(), PDO::PARAM_STR); $stmt->execute(); return $stmt->fetchAll(PDO::FETCH_CLASS, Bug::class); } catch (PDOException $e) { if ($this->isGrammaticalError($e->getCode())) { throw new LogicException($e->getMessage(), $e->errorInfo[1], $e); } throw $e; } } ɹpOE"MMϝιουͷࣄޙ৚݅Λදݱ͢Δ
  99. } catch (PDOException $e) { if ($this->isGrammaticalError($e->getCode())) { throw new

    LogicException($e->getMessage(), $e->errorInfo[1], $e); } throw $e; } ɹpOE"MMϝιουͷࣄޙ৚݅Λදݱ͢Δ SQLSTATE の値を調査し、 PDOException の内容が例外で はなくあきらかにバグの場合は、 バグを示す LogicException で包んで投げ直している。 その際に第3引数を忘れずに設定し、スタックトレースを つなぐ
  100. ୈ෦·ͱΊόάͱྫ֎Λ۠ผ͠ɺ ͞Βʹ୭ͷ੹೚͔΋ݟ෼͚ΒΕΔΑ͏ʹ͢Δ IUUQRJJUBDPN,PLVEPSJJUFNTBDGBC

  101. ·ͱΊ

  102. public static function findAll($params) { if (is_null($params)) { throw new

    InvalidArgumentException('params should not be null'); } if (!is_array($params)) { throw new InvalidArgumentException('params should be an array'); } if (count($params) !== 2) { throw new InvalidArgumentException('params should be have exact two items'); } if (!array_key_exists('assignedTo', $params) || !array_key_exists('status', $params)) { throw new InvalidArgumentException('params should have key `assignedTo` and `status` only'); } if (!is_int($params['assignedTo'])) { throw new InvalidArgumentException('params[`assignedTo`] should be an integer'); } if (!is_string($params['status'])) { throw new InvalidArgumentException('params[`status`] should be a string'); } if (!in_array($params['status'], ['OPEN', 'NEW', 'FIXED'], true)) { throw new InvalidArgumentException('params[`status`] should be in `OPEN`,`NEW`,`FIXED`'); } global $CONF; if (!isset($CONF['dsn'])) { throw new LogicException('config key `dsn` not found'); } if (!isset($CONF['usr'])) { throw new LogicException('config key `usr` not found'); } if (!isset($CONF['passwd'])) { throw new LogicException('config key `passwd` not found'); } $pdo = new PDO($CONF['dsn'], $CONF['usr'], $CONF['passwd'], [ PDO::ATTR_EMULATE_PREPARES => false ]); $sql = 'SELECT bug_id, summary, date_reported FROM Bugs WHERE assigned_to = :assignedTo AND status = :status'; $stmt = $pdo->prepare($sql); $stmt->execute($params); if (!class_exists('Bug')) { throw new LogicException('class `Bug` does not exist'); } return $stmt->fetchAll(PDO::FETCH_CLASS, Bug::class); } public function __construct(PDO $pdo) { $this->pdo = $pdo; } public function findAll(int $assignedTo, Status $status) { $sql = 'SELECT bug_id, summary, date_reported FROM Bugs WHERE assigned_to = :assignedTo AND status = :status'; $stmt = $this->pdo->prepare($sql); $stmt->bindValue(':assignedTo', $assignedTo, PDO::PARAM_INT); $stmt->bindValue(':status', $status->value(), PDO::PARAM_STR); $stmt->execute(); return $stmt->fetchAll(PDO::FETCH_CLASS, Bug::class); } ୈ෦·ͱΊ༧๷ʹউΔ๷ޚͳ͠
  103. IUUQTXXXBTURCPSHQSFTTSPPN*452#@$FSUJpDBUJPO@/FXT@@IUNM ୈ෦·ͱΊlGBJMGBTUz ো֐Λ๊͑ͯ த్൒୺ʹಈ͍͍ͯΔϓϩάϥϜΑΓ΋ ࢮΜͩϓϩάϥϜͷ΄͏͕ μϝʔδ͸গͳ͍

  104. ୈ෦·ͱΊόάͱྫ֎Λ۠ผ͠ɺ ͞Βʹ୭ͷ੹೚͔΋ݟ෼͚ΒΕΔΑ͏ʹ͢Δ IUUQRJJUBDPN,PLVEPSJJUFNTBDGBC

  105. lݡ໌ͳιϑτ΢ΣΞٕज़ऀʹ ͳΔͨΊͷୈҰา͸ɺಈ͘ϓ ϩάϥϜΛॻ͘͜ͱͱਖ਼͍͠ ϓϩάϥϜΛద੾ʹ࡞੒͢Δ ͜ͱͷҧ͍Λೝࣝ͢Δ͜ͱz Š."+BDLTPO  ͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠