Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

࿨ా୎ਓ JEUXBEB !U@XBEB HJUIVCUXBEB

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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-ΞϯνύλʔϯʱͷͻͲ͍ ίʔυྫΛΞϨϯδͯ͠ॻ͍͍ͯ·͢ ɹͱ͋Δͱ͜Ζʹɺ͜Μͳίʔυ͕͋Γ·ͨ͠ # " %

Slide 5

Slide 5 text

$ 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 ) ) ɹॲཧ͕੒ޭ͢Δͱɺ͜Μͳײ͡ɻ

Slide 6

Slide 6 text

ಥવͰ͕͢ ͜͜Ͱ ΫΠζͰ͢

Slide 7

Slide 7 text

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); } ⏰੍ݶ࣌ؒඵ ɹॲཧࣦഊͷݪҼʹͳΔՄೳੑ͕͋Δͷ͸Ͳͷߦ # " %

Slide 8

Slide 8 text

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౳Ωʔ໊͕มߋ͞Εͨ

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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ͷ஋͕จࣈྻʹม׵ෆೳ  ͜͜Ͱ σʔλϕʔε઀ଓΤϥʔ

Slide 11

Slide 11 text

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Ϋϥε͕ະఆٛ  ͜͜Ͱ σʔλϕʔε઀ଓΤϥʔ ˞ઃఆʹΑΔ

Slide 12

Slide 12 text

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); } ɹॲཧࣦഊͷݪҼʹͳΔՄೳੑ͕͋Δͷ͸Ͳͷߦ # " % ᶃ ᶄ ᶅ ᶆ ͑ͬɺ͜Μͳʹ͋Δͷ 

Slide 13

Slide 13 text

ɹ͜ͷͳ͔Ͱ΋ಛʹखڧ͍ঢ়گ͸ͲΕ σʔλϕʔε઀ଓཱࣦ֬ഊ AVTSA AQBTTXEA౳Ωʔ໊͕มߋ͞Εͨ ςʔϒϧ໊΍ΧϥϜ໊͕୭͔ʹมߋ͞Εͨ QBSBNT͕OVMM QBSBNTͷΩʔ໊΍਺ͷෆҰக QBSBNTͷ஋͕จࣈྻʹม׵ෆೳ #VHΫϥε͕ະఆٛ ్தͰσʔλϕʔε઀ଓΤϥʔ

Slide 14

Slide 14 text

ɹࢲݟͰ͸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ͷΩʔ໊΍਺ͷෆҰக # " %

Slide 15

Slide 15 text

$ php example.php PHP Warning: PDOStatement::execute(): SQLSTATE[HY093]: Invalid parameter number: parameter was not defined in example.php Array ( ) ɹΩʔ໊΍਺Λؒҧ࣮͑ͯߦ͢ΔͱͲ͏ͳΔ ཪͰͬͦ͜Γܯࠂ͕ग़Δ͚ͩͳͷ  ۭ഑ྻ͕ฦͬͯ͘Δͷ  ਖ਼ৗܥͱݟ෼͚͕͔ͭͳ͘ͳ͍  

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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); } ɹॲཧࣦഊͷݪҼʹͳΔՄೳੑ͕͋Δͷ͸Ͳͷߦ # " % ᶃ ᶄ ᶅ ᶆ ݱ࣮ੈք΁Α͏ͦ͜

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

w ʮ๷ޚతϓϩάϥϛϯάʯͱ͸ɺϓϩάϥϛϯάʹ ରͯ͠๷ޚతʹͳΔ͜ͱɺͭ·Γʮͦ͏ͳΔ͸ͣ ͩʯͱܾΊ͚ͭͳ͍͜ͱ w ๷ޚతϓϩάϥϛϯάͷࠜఈʹ͋Δͷ͸ɺϧʔνϯ ʹෆਖ਼ͳσʔλ͕౉͞Εͨͱ͖ʹɺͦΕ͕ଞͷϧʔ νϯͷ͍ͤͰ͋ͬͨͱͯ͠΋ɺඃ֐Λड͚ͳ͍Α͏ ʹ͢Δ͜ͱ w ͜ͷͨΊɺ w ֎෦ιʔε͔Βͷσʔλͷ஋Λ͢΂ͯ֬ೝ͢Δ w ϧʔνϯͷ͢΂ͯͷೖྗҾ਺ͷ஋Λ֬ೝ͢Δ w ෆਖ਼ͳೖྗΛॲཧ͢Δํ๏Λܾఆ͢Δ ๷ޚతϓϩάϥϛϯά

Slide 26

Slide 26 text

ڱٛͷ ๷ޚతϓϩά ϥϛϯά΁ͷޡղ

Slide 27

Slide 27 text

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 ]); ɹͨͩͻͨ͢ΒೖྗΛνΣοΫ͠Α͏ͱͨ͠Γ # " %

Slide 28

Slide 28 text

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); ɹෆਖ਼ͳೖྗ͕͋ͬͯ΋ࣗ෼ͰͳΜͱ͔͠Α͏ͱͨ͠Γ # " %

Slide 29

Slide 29 text

/** * 担当者, ステータスに合致する 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 ]); ɹυΩϡϝϯτͰؒҧ͍΍͢͞Λิ͓͏ͱͨ͠Γ # " %

Slide 30

Slide 30 text

๷ޚతϓϩάϥϛϯάͱ͸ ѱ͍ίʔυʹឺ૑ߣΛ͋ͯ Δ͜ͱͰ͸ͳ͍

Slide 31

Slide 31 text

w ʮ๷ޚతϓϩάϥϛϯάʯͱ͸ɺ໰୊ൃੜΛ ࣄલʹ๷͝͏ͱ͍͏ίʔσΟϯάελΠϧ w Մಡੑͷߴ͍ίʔυͱద੾ͳ໋໊نଇ w શͯͷؔ਺ͷ໭Γ஋ΛνΣοΫ w σβΠϯύλʔϯͷ࠾༻ w ཁ͢Δʹɺྑࣝ͋Δ࣮ફͷੵΈॏͶͰ͋Δ w ๷ޚతϓϩάϥϛϯά͸ɺਖ਼͍͠ίʔυ࡞੒ ͷͨΊͷن཯ΛϓϩάϥϚ͕Ұ؏ͯ͠ద༻͢ ΔͨΊͷҰछͷίʔσΟϯάඪ४ ๷ޚతϓϩάϥϛϯά

Slide 32

Slide 32 text

wྑ͍ΠϯλϑΣʔεͱ͸࣍ͷͭͷ ৚݅Λຬͨ͢ΠϯλϑΣʔε wਖ਼͘͠࢖༻͢Δํ͕ૢ࡞ϛεΛ ͢ΔΑΓ؆୯ wޡͬͨ࢖͍ํΛ͢Δ͜ͱ͕ࠔ೉ ͖ͷ͜ਖ਼͍͠࢖͍ํΛ؆୯ʹɺ ޡͬͨ࢖͍ํΛࠔ೉ʹ

Slide 33

Slide 33 text

ܕͷ੍ݶ ܕએݴ

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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 

Slide 36

Slide 36 text

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);

Slide 37

Slide 37 text

஋ͷ੍ݶ &OVN

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

IUUQRJJUBDPN)JSBLVJUFNTFCEDBBGF

Slide 40

Slide 40 text

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࣮૷Λ গ͠ΞϨϯδͯ͠ ࢖ͬͯΈΔ

Slide 41

Slide 41 text

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'); ɹ͋Β͔͡Ίఆٛ͞Εͨ஋͚ͩΛΠϯελϯεԽͰ͖Δ

Slide 42

Slide 42 text

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); } ɹ૝ఆ͠ͳ͚Ε͹ͳΒͳ͍ঢ়گ͕͞Βʹݮͬͨ

Slide 43

Slide 43 text

σʔλϕʔε઀ଓཱࣦ֬ഊ AVTSA AQBTTXEA౳Ωʔ໊͕มߋ͞Εͨ ςʔϒϧ໊΍ΧϥϜ໊͕୭͔ʹมߋ͞Εͨ QBSBNT͕OVMM QBSBNTͷΩʔ໊΍਺ͷෆҰக QBSBNTͷ஋͕จࣈྻʹม׵ෆೳ #VHΫϥε͕ະఆٛ ్தͰσʔλϕʔε઀ଓΤϥʔ ɹޡΓ΍͍͢ΠϯλʔϑΣΠεʹىҼ͢ΔॲཧࣦഊΛ๾໓ ✔ ✔ ✔

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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ੜ੒ͱઃఆͷ੹຿Λ֎෦ʹग़͠ɺίϯετϥΫλͰड͚औΔ

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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); } ୈ෦·ͱΊ༧๷ʹউΔ๷ޚͳ͠

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

GBJMGBTU ߈ܸతϓϩάϥϛϯά

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

IUUQTXXXBTURCPSHQSFTTSPPN*452#@$FSUJpDBUJPO@/FXT@@IUNM ো֐Λ๊͑ͯ த్൒୺ʹಈ͍͍ͯΔϓϩάϥϜΑΓ΋ ࢮΜͩϓϩάϥϜͷ΄͏͕ μϝʔδ͸গͳ͍

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

w ࠷దͳΤϥʔॲཧ͸Τϥʔ͕ൃੜͨ͠ιϑτ΢ΣΞ ͷछྨʹΑΓҟͳΔ w ਖ਼౰ੑͱ͸ɺෆਖ਼֬ͳ݁ՌΛܾͯ͠ฦ͞ͳ͍͜ͱΛ ҙຯ͢Δɻෆਖ਼֬ͳ݁ՌΛฦ͘͢Β͍ͳΒɺԿ΋ฦ ͞ͳ͍ํ͕·͠Ͱ͋Δ w ݎ࿚ੑͱ͸ɺιϑτ΢ΣΞͷ࣮ߦΛܧଓͰ͖ΔΑ͏ ʹखΛਚ͘͢͜ͱͰ͋ΔɻͦΕʹΑͬͯෆਖ਼͕֬݁ Ռ͕΋ͨΒ͞ΕΔ͜ͱ͕͋ͬͯ΋͔·Θͳ͍ w ҆શੑ ΍ਖ਼֬ੑ Λॏࢹ͢ΔΞϓϦέʔγϣϯͰ ͸ɺݎ࿚ੑΑΓ΋ਖ਼౰ੑ͕༏ઌ͞ΕΔ܏޲ʹ͋Δ w ίϯγϡʔϚΞϓϦέʔγϣϯͰ͸ɺਖ਼౰ੑΑΓ΋ ݎ࿚ੑ͕༏ઌ͞ΕΔ܏޲ʹ͋Δ ਖ਼౰ੑͱݎ࿚ੑ

Slide 56

Slide 56 text

ݸʑͷΫϥε͸ਖ਼౰ੑΛॏࢹ͠ɺ ݎ࿚ੑ͸ΞʔΩςΫνϟϑϨʔϜϫʔΫ౳Ͱ อূ͢Δͷ͕Φεεϝ ྫݸʑͷΫϥε͸GBJMGBTUݪଇͰॻ͖ɺ8FC ϑϨʔϜϫʔΫ΍άϩʔόϧϋϯυϥ͕Ωϟον ͯ͠Τϥʔը໘౳Λग़͢੹຿Λෛ͏ ɹϛΫϩͰ͸ਖ਼౰ੑΛॏࢹ͠ɺϚΫϩͰ͸ݎ࿚ੑΛॏࢹ͢Δ

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

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ฦ͠

Slide 60

Slide 60 text

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ฦ͠

Slide 61

Slide 61 text

໭Γ஋ͷऑ఺ ໭Γ஋͸ ɹίʔυ͕ංେԽ͕ͪ͠ ɹແࢹ͞Ε΍͍͢ ɹͨͱ͑ॏେͳ໰୊͕જΜͰ͍ͯ ΋ɺ໭Γ஋͚ͩͰ͸఻ΘΓʹ͍͘ ࣮ࡍ$ݴޠͷؔ਺ͷ໭Γ஋ͷதʹ͸ʮແࢹ͢Δͷ͕ී ௨ʯͱ͞Ε͍ͯΔ΋ͷ͑͋͞Δ

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

wྫ֎ͷ࠷େͷར఺͸ɺແࢹͰ͖ͳ͍ ํ๏ͰΤϥʔঢ়ଶΛ஌ΒͤΔ͜ͱͰ ͋Δ ΦϒδΣΫτࢦ޲ೖ໳ୈ൛  wྫ֎ΛނҙʹѲΓͭͿ͢͜ͱ͸Մೳ ͕ͩɺͦ͏͍͏ίʔυ͕ॻ͔Ε͍ͯ Δͱ͖͸ɺॻ͖खͷ࢟੎ʹ໰୊͕͋ Δͱ͙͢ʹΘ͔Δ ͖ͷ͜ ྫ֎ͷར఺

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

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

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

1)1ͷBTTFSU 1 ) 1  IUUQQIQOFUNBOVBMKBGVODUJPOBTTFSUQIQ

Slide 71

Slide 71 text

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 で明示する

Slide 72

Slide 72 text

$ 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 

Slide 73

Slide 73 text

1)1ͷBTTFSUͷઃఆ 1 ) 1  PHP5 との互換性を保つためデフォルトでは警告になっている。 つまり php.ini で assert.exception = 1 にすべし IUUQQIQOFUNBOVBMKBGVODUJPOBTTFSUQIQ

Slide 74

Slide 74 text

$ 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 

Slide 75

Slide 75 text

w ද໌͸ίϛϡχέʔγϣϯͱσόοάͷπʔϧͱ ͯ͠ಇ͘ w ίϛϡχέʔγϣϯͷ؍఺Ͱ͸ɺද໌Λॻ͘͜ͱ ʹΑͬͯɺͦͷίʔυΛॻ͍ͨͱ͖ͷલఏΛίʔ υͷಡΈख͕ཧղ͠΍͘͢ͳΔ w σόοάͷ؍఺Ͱ͸ɺόάΛͦͷݪҼʹ͍ۙͱ͜ ΖͰൃݟ͠΍͘͢ͳΔ w ςετίʔυΛॻ͍ͯ͋Ε͹ɺσόοάͷࢧԉ͸ ͞΄ͲॏཁͰ͸ͳ͍͕ɺͦΕͰ΋ίϛϡχέʔ γϣϯͷ؍఺ʹ͓͚Δද໌ͷՁ஋͸ɺґવͱͯ͠ ༗ޮ ද໌ͷϝϦοτ

Slide 76

Slide 76 text

ྫ֎ͱද໌ͷ࢖͍෼͚ w ຊདྷͷΤϥʔॲཧʹද໌Λ࢖ͬͯ͸͍ ͚·ͤΜɻද໌͸ى͜Γಘͳ͍͜ͱΛ νΣοΫ͢ΔͨΊͷ΋ͷͰ͢ ৽૷൛ ୡਓϓϩάϥϚʔ  w ൃੜ͕༧૝͞ΕΔঢ়گʹ͸Τϥʔॲཧ ίʔυΛ࢖༻͠ɺൃੜͯ͠͸ͳΒͳ͍ ঢ়گʹ͸ΞαʔγϣϯΛ࢖༻͢Δ $0%&$0.1-&5&ୈ൛

Slide 77

Slide 77 text

w͋·Γʹ΋๷ޚతͳϓϩάϥϛϯ ά΋ɺͦΕ͸ͦΕͰ໰୊ wҾ਺Λߟ͑ΒΕΔݶΓͷ৔ॴͰ ߟ͑ΒΕΔݶΓͷํ๏ͰνΣο Ϋ͢Ε͹ɺϓϩάϥϜ͸ංେԽ ͠௿଎ʹͳΔ BTTFSUJPOΛೖΕ͗͢Δͱ ௿଎ʹͳΔͷͰ͸ʁ ʮ๷ޚతϓϩάϥϛϯάʹର͢Δ๷ޚʯΑΓ

Slide 78

Slide 78 text

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

Slide 79

Slide 79 text

ɹ[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);

Slide 80

Slide 80 text

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 と設定すれば表明を除去できる

Slide 81

Slide 81 text

ද໌ʹҾ͖౉͢৚݅ʹ͸෭࡞༻͕ ͋ͬͯ͸͍͚·ͤΜɻίϯύΠϧ࣌ʹ ද໌͕Φϑʹ͞ΕΔ৔߹΋͋Δͱ͍ ͏఺Λ๨Εͯ͸͍͚·ͤΜɻ ͭ·ΓBTTFSUதʹ͸࣮ߦʹඞཁͳ ίʔυΛهड़ͯ͠͸͍͚ͳ͍ͷͰ͢ ʮώϯτ΋͠ى͜Γಘͳ͍ͱ͍͏ͷͰ͋Ε͹ɺද໌Λ༻͍ͯͦΕΛอূ͢Δ͜ͱʯΑΓ ɹΦϑʹ͞ΕΔ͜ͱΛҙࣝͯ͠ॻ͘ 副作用の例: assert(end($users));

Slide 82

Slide 82 text

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

Slide 83

Slide 83 text

IUUQTXXXBTURCPSHQSFTTSPPN*452#@$FSUJpDBUJPO@/FXT@@IUNM ୈ෦·ͱΊlGBJMGBTUz ো֐Λ๊͑ͯ த్൒୺ʹಈ͍͍ͯΔϓϩάϥϜΑΓ΋ ࢮΜͩϓϩάϥϜͷ΄͏͕ μϝʔδ͸গͳ͍

Slide 84

Slide 84 text

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

Slide 85

Slide 85 text

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

Slide 86

Slide 86 text

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

Slide 87

Slide 87 text

ܖ໿ʹΑΔઃܭ

Slide 88

Slide 88 text

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

Slide 89

Slide 89 text

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

Slide 90

Slide 90 text

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

Slide 91

Slide 91 text

੒ޭࣦഊόάྫ֎ IUUQRJJUBDPN,PLVEPSJJUFNTBDGBC

Slide 92

Slide 92 text

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ܥόά

Slide 93

Slide 93 text

w࣮ߦ࣌ͷද໌ҧ൓ ΍ɺόάΛࣔͨ͢Ί ͷྫ֎ ͸ɺͦͷιϑτ΢ΣΞʹόά͕ ͋ΔূڌͰ͋Δ wࣄલ৚݅ҧ൓͸ݺͼग़͠ଆʹόά͕ ͋ΔূڌͰ͋Δ wࣄޙ৚݅ҧ൓͸ڙڅऀଆʹόά͕͋ ΔূڌͰ͋Δ ܖ໿ʹΑΔઃܭ %FTJHOCZ$POUSBDU %C$

Slide 94

Slide 94 text

ɹ#VHΫϥε͕ະఆٛͷঢ়گʹ͸Ͳ͏උ͑Δ $ php example.php PHP Fatal error: Class 'Bug' not found in /path/to/example.php on line 85 ౴͑ͳʹ΋͠ͳ͍ɻ ͜Ε͸ྫ֎తঢ়گͰ͸ͳ͘ʢจࣈ௨ΓʣόάͰ ͋ΓɺϓϩάϥϛϯάϛεͳͷͰɺΤϥʔϋϯ υϦϯάͯ͠͸ͳΒͳ͍ɻͳʹ΋ͤͣɺ଎΍͔ ʹམͱ͢ɻGBJMGBTU͕ॏཁɻ

Slide 95

Slide 95 text

ίϯετϥΫλͷ ܖ໿

Slide 96

Slide 96 text

/** * 検索処理に使用する 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; } ɹίϯετϥΫλͷࣄલ৚݅Λදݱ͢Δ

Slide 97

Slide 97 text

pOE"MMϝιου ͷܖ໿

Slide 98

Slide 98 text

/** * 指定された担当者 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ϝιουͷࣄޙ৚݅Λදݱ͢Δ

Slide 99

Slide 99 text

} 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引数を忘れずに設定し、スタックトレースを つなぐ

Slide 100

Slide 100 text

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

Slide 101

Slide 101 text

·ͱΊ

Slide 102

Slide 102 text

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); } ୈ෦·ͱΊ༧๷ʹউΔ๷ޚͳ͠

Slide 103

Slide 103 text

IUUQTXXXBTURCPSHQSFTTSPPN*452#@$FSUJpDBUJPO@/FXT@@IUNM ୈ෦·ͱΊlGBJMGBTUz ো֐Λ๊͑ͯ த్൒୺ʹಈ͍͍ͯΔϓϩάϥϜΑΓ΋ ࢮΜͩϓϩάϥϜͷ΄͏͕ μϝʔδ͸গͳ͍

Slide 104

Slide 104 text

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

Slide 105

Slide 105 text

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