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

帰ってきた!平成最後のオレオレフレームワークの作り方

uzulla
March 31, 2019

 帰ってきた!平成最後のオレオレフレームワークの作り方

PHPerKaigi 2019
2019/03/31 Track A
uzulla

uzulla

March 31, 2019
Tweet

More Decks by uzulla

Other Decks in Technology

Transcript

  1. ؼ͖ͬͯͨʂ
    ฏ੒࠷ޙͷ
    ΦϨΦϨϑϨʔϜϫʔΫͷ
    ࡞Γํ
    » PHPerKaigi 2019
    » 2019/03/22
    » @uzulla

    View Slide

  2. ʮؼ͖ͬͯͨʯʁ
    » ʮPHPerਓੜɺҰ౓͸ϑϨʔϜϫʔΫΛ࡞͓ͬͯ͜
    ͏ʂʯ
    » PHPΧϯϑΝϨϯε๺ւಓ 2016
    » https://speakerdeck.com/uzulla/phperren-
    sheng-du-hahuremuwakuwozuo-tuteokou
    » ࣍ͷϖʔδ͔ΒμΠδΣετ

    View Slide

  3. View Slide

  4. View Slide

  5. View Slide

  6. View Slide

  7. View Slide

  8. View Slide

  9. ࠓ೔ͷ΋ͷΑΓॳ৺ऀ޲͚ͳ
    ͷͰɺͥͻɻ
    » ࿩Λ໭͠·͢ɻ

    View Slide

  10. #ΦϨΦϨϑϨʔ
    ϜϫʔΫ ͱ͸ʁ
    » (ϑϨʔϜϫʔΫ(ҎޙFW)ͷઆ໌
    ͸͠·ͤΜ)
    » ࣗ෼Ͱ࡞ͬͨFW
    -> ΦϨΦϨFW
    » ݱ୅Ͱ͸ϑϨʔϜϫʔΫ͸
    ʮબͿʯ΋ͷ
    » ੲ͸ϑϨʔϜϫʔΫ͸ͳ͔ͬͨ
    » ΈΜͳϑϨʔϜϫʔΫΛͭͬ͘
    ͨ΋Μ͡Ό…ʢॾઆ͋Γ·͢ʣ

    View Slide

  11. » جຊతʹɺݱ୅Ͱ͸ɺΦϨΦϨ͸ආ͚Δ΂͖ߦҝͱ
    ͞ΕΔ
    » ࣗզͷڧ͍FW͸Έͳ͕޾ͤʹͳΕͳ͍͜ͱ͕ଟ
    ͍

    View Slide

  12. ͦ΋ͦ΋ɺFWͷར఺͕େମͳ͘ͳΔ
    » ੜ࢈ੑɺ඼࣭ͷ޲্
    » ݱ࣮Ͱςετ͞ΕͨϥΠϒϥϦ
    » ϕλʔϓϥΫςΟεͳख๏
    » େن໛։ൃͷجૅ
    » υΩϡϝϯτͷ੔උ
    » ΤϯδχΞͷֶश
    » ΤίγεςϜ
    » ར༻ऀͷϒϩά΍࣭໰αΠτͰͷճ౴
    » ϓϥάΠϯͷ๛෋͞

    View Slide

  13. ΦϨΦϨϑϨʔϜϫʔΫͷར఺ʢʁʣ
    » ͦͷਓ͕͕Μ͹Ε͹ϝϯς͕ଓ͘
    » ʢεΩϧͷ͋Δਓ͕ͦΜͳۀ຿ʹ͔·͚͍ͯΔΘ͚ʹ
    ΋…ʣ
    » ʮͦͷ࣌ͷʯ(ఆܗ)ۀ຿ʹదͨ͠ઃܭʹͳΔ
    » ʢ࣌୅͸มΘΓ·͢ͷͰ…Ψϥέʔ޲͚ػೳ͕ࠓ͋ͬͯ
    ΋…ʣ
    » OSSʹཔΒͳ͍ͰࡁΉ
    » ʢʮϥΠηϯεͬͯΑ͘Θ͔Βͳ͍ΜͩΑͶʯʮͳΔ΄
    Ͳʯʣ

    View Slide

  14. ͳͷʹɺͳͥࣗ࡞ͯ͠͠·͏ͷ͔ʁʁ
    » ΦϨΦϨϑϨʔϜϫʔΫΛʮ࡞Δʯͱຊਓͷܦݧ஋͸૿͑
    Δ
    » ʢධՁ͞ΕΔ͔͸ผʣ
    » ൚༻తͳྗͷ޲্
    » ຊਓͷ૝૾ྗɾίʔυϦʔσΟϯάͷεΩϧΞοϓ
    » ίϐʔ͢Δͷ΋؆୯Ͱ͸ͳ͍
    » ͳʹ͔͏·͍͔͘ͳ͍࣌ɺFWͷίʔυΛಡΊΔ
    » ʮͳ͔ͥ͜ΕͰ͏͘͝ʯ͕ݮΔ

    View Slide

  15. ʮͪΐͬͱ·ͬͯʂʯ
    » ͋ͳͨͷʮࠓͷ࢓ࣄʯ͸ΦϨΦϨϑϨʔϜϫʔΫΛ࡞Δ
    ͜ͱ͔ʁ
    » ੈքฏ࿨ʹ͸ڵຯ͕ͳ͍ͷ͔ʁ
    » ࣗ୐ͰӅΕͯͬͦ͜Γ΍Γ·͠ΐ͏
    » Ұ౓΋࡞ͬͨ͜ͱແ͍ͷ͸Ͳ͏ͳͷ͔ʁʢ࿝֐ൃݴʣ
    » ؾ߹Λ͍Ε͍͚ͯ͹ɺΦϨΦϨ͔Β௒͍͑ͯ͘͜ͱ
    ΋…ʂ
    » ʮͦͷ֮ޛ͸͋Δ͔ʁʯʮͳ͍Θʔʔʯ

    View Slide

  16. » https://twitter.com/excite__pr/status/
    1082482594401288193

    View Slide

  17. ΍͍͖ͬͯ·͠ΐ͏

    View Slide

  18. ॳ৺ऀ޲͚ɺΦϨΦϨ࡞੒ʹ͋ͨͬͯඞཁͳ৺ߏ
    ͑
    » ंྠ FWͷ࠶ൃ໌ʹ͋ͨͬͯͷ৺ߏ͑Λ఻͑·͢

    View Slide

  19. ंྠ͸࠶ൃ໌͢Δ΋ͷ
    » ਓؾͷंྠ͸།Ұ࠷ߴͷंྠͰ͸ͳ͍
    » ͋ͳͨͷυϝΠϯʹϚον͍ͯ͠ͳ͍͔΋
    » ࠷ߴ͸৭ʑ༗Δ
    » ྫɿάϦοϓྗ͕௿ͯ͘΋ɺύϯΫ͠ͳ͍λΠϠ͕͍͍
    » ྫɿτϥϯΫʹੵΉۓٸ༻͔ͩΒখ͍͞ͷ͕ྑ͍
    » ଞਓ͕࠷ߴͱײ͡Δඞཁ͸ͳ͍
    » ʮ˓˓ͷFWͷ͜Ε͸࠷ߴʂʯ͸ΦϨΦϨͱ૬൓͠ͳ͍
    » श࡞ͳΒʮࣗ෼ͷʯ࠷ߴΛ໨ࢦ͢ͱΑ͍

    View Slide

  20. ंྠ͸ंྠͩ
    » Ͱ͖Ε͹ૉ௚ʹؙ͘࡞Ζ͏
    » ߴػೳͰͳͯ͘΋ɺؙ͚Ε͹ंྠʹ͸ͳΔ
    » ͨͱ͑͹ɺΑ͋͘ΔϧʔλʔΛ࡞Δ(͚ͭΔ)
    » ʮͳΜͰଞͷϑϨʔϜϫʔΫ͸͜͏ͳͬͯͳ͍Μͩʁ
    ԶͳΒ͜͏͢Δʂʯ

    View Slide

  21. » ʮಉ྅ʹ࠘·Εͳ͍ΦϨΦϨ΋͋Δ͸ͣͳΜͩɺͦ
    ͏ݴͬͯஉ͸εύήοςΟͷ৿ʹফ͑ͨ…ʯ
    » ͩΕ΋΍͍ͬͯͳ͍ઃܭ͸᠘͔΋ɺ஫ҙʂ

    View Slide

  22. Α͋͘ΔਥೋපɺREST(ful)ฤ
    » (APIʹ͓͍ͯ͸)REST෩ͳύεύϥϝʔλʹ΋ٙ໰͕͋Δ
    » /book/1ͱ͔΍Δͱɺཪଆʹbookςʔϒϧͷid1͕ඞਢͱ͔
    ͋Γ͕ͪ
    » ϦιʔεʢDBͷςʔϒϧͱີ݁߹ʣࢤ޲͸ݶք͕͋ΔͷͰ
    ͸
    » ʮ_methodͬͯͳΜͩΑϫϩλɺେࣗવʹPATCHͳ͍΍Ζʯ
    » ʮഁյ͕ͳ͍ͳΒGETʯͷ༥௨ͷ͖͔ͳ͞
    » ߴ౓Ͱগͳ͍ίʔυΑΓɺόΧͰ΋Θ͔Δྔͷ͋Δίʔυ
    ͷ΄͏͕ͳΜͱ͔ͳΓ΍͍͢ʢओ؍ʣ

    View Slide

  23. ઌߦ੡඼Λ͔͍ͭ͜ͳͤ
    » ͔͍ͭ͜ͳͤͳ͍͍͍Θ͚ͰΦϨΦϨΛͭͬͯ͘͸ͳ
    Β͵
    » (͢ΔͱʮΦϨΦϨ͍Βͳ͍ͳʁʯͱ͍͏ฏ࿨ͳॴʹ
    ߦ͖ண͘ࣄ΋͋Γ·͢ɻ)

    View Slide

  24. ंྠ͸෦඼ͩ(ओ؍)
    » ʮಛ஫඼ʯ͸ආ͚Δ΂͖
    » ઃܭͷ࣮ફςετෆ଍
    » ࠷ߴͷ෦඼͸൚༻෦඼ͩ
    » ୅ସ͕ޮ͘

    View Slide

  25. » ͨͱ͑͹ϧʔλʔ
    » ΄ͱΜͲͷ΋ͷ͸IFઃܭ͕ࣅ͍ͯΔ
    » ʢݱ࣮ੈքͰ࣮ূ͞Εͨ࢖͍΍͢͞ʣ
    » ަ׵Ͱ͖Δ
    » ʢAPI͸ۃ୺ʹ͸มΘΒͳ͍ͷͰɺ࡞ͬͯࠩ͠ସ
    ͑΍͍͢ʣ
    » ࢖͍ํ΋ʹͨΓΑͬͨΓ
    » ʢֶशίετ͕௿͍ʣ

    View Slide

  26. ৺ߏ͑·ͱΊ
    » ʮੈؒͷ࠷ߴʯ͸Αͦʹஔ͘
    » श࡞͔ͩΒͦ͜
    » ʮ͋Ε͕ͳ͍ɺ͜Ε͕ͳ͍ʯ͸ແ༻
    » Ͳͷ෦෼ͷந৅౓Λ্͛Δ͔͸ɺҊ݅ʹΑΔ
    » ͱ͸͍͑ɺయܕྫΛ໛฿͢Δͱഁ୼͠ਏ͍
    » (ΦϨΦϨͰഁ୼Λؾʹ͢Δͷ͔ʁ)

    View Slide

  27. ॳ৺ऀ޲͚ͷखͷ෇͚ํ
    » ॳ৺ऀ͸طଘͷϑϨʔϜϫʔΫͰΞϓϦΛ࡞ͬͯΈΔ
    ͱΑ͍
    » ඞཁͳॴ͕ݟ͑ͯ͘Δ
    » ؾʹ৯Θͳ͍෦෼΋ݟ͑ͯ͘Δʢ͕ࣗ͜͜ݾຬ଍
    ͷͨΊʹॏཁʣ
    » ʢ΋͠ຬ଍Ͱ͖Ε͹ؙṶ͚ʣ
    » ͦΕΛΦϨΦϨFWʹҠ২͠Α͏ʂ

    View Slide

  28. ॱ൪ʹͭͬͯ͘ɺࠩ͠ସ͍͑ͯ͘
    » શ෦ΛҰؾʹͭ͘Βͳ͍ͱಈ͔ͳ͍ͱͭΒ͍
    » ͪΐͬͱͮͭஔ͖׵͍͑ͯ͘
    » (͢ΔͱɺϑϧελοΫͰͳ͘ɺ෦඼୯ҐͷFW͕
    Α͍Ͷʁ)
    » Ͱ΋ɺπΪϋΪͬΆ͘ͳΔΑͶ…ʁ
    » ϑϧελοΫ͸ࣗ৴͕Ͱ͖͔ͯΒ΍Ζ͏

    View Slide

  29. ॳ৺ऀ͕(؆୯͔ͩΒ)࡞Δ΂͖ػೳ
    » ϧʔλʔ
    » όϦσʔλʔ
    » DI෩ίϯςφ
    » ςϯϓϨʔτΤϯδϯ…ͷϔϧύʔ

    View Slide

  30. Ϥγʂ
    » ʮLaravelΈ͍ͨͳςϯϓϨʔτΤϯδϯ࡞Ζ͏ʯ
    » ʮLaravelΈ͍ͨͳDIΛ࡞Ζ͏ʯ
    » ʮLaravelΈ͍ͨͳORMΛ࡞Ζ͏ʯ
    » ʮΑ͠ʂ-BSBWFMͷίʔυಡ΋͏ʂʯ

    View Slide

  31. …ʢॳ৺ऀʹ͸ʣແཧͰ͸ʁʁ
    » ࢖͏ػೳ͕ࣗ෼Ͱͭ͘Εͳ͍ʁ
    » ΦϨΦϨ͔ͩΒఘΊΔʁ
    » SUGOIϥΠϒϥϦΛ࢖͏ʁ
    » ࢓༷ଆΛม͑Δʁ
    » खஈ͸ͳΜͰ΋ΞϦͩΑɺͩͬͯΦϨΦϨͩ΋Μ
    » (ྫྷ੩ʹͳͬͯ͜͜ͰΦϨΦϨ࡞੒ΛࢭΊΔ((?ʁ

    View Slide

  32. ॳ৺ऀ͕ݟΔ΂͖ϑϨʔϜϫʔΫ
    » ݹ͍Μ͚ͩͲɺFWͷίʔυΛಡΜͩ͜ͱ͕ͳ͍ͳΒ·ͣ͸͜ͷลΓΛ
    ಡΉͱྑ͛͞
    » ੿࡞ͷOre1,2
    » https://github.com/uzulla/Ore
    » https://github.com/uzulla/Ore2
    » Limonade
    » Slim Frameworkͷ2.xܥ
    » phpixieͷ2.xܥ
    » ͜ΕΒ͸ൺֱతಡΈ΍͍͚ͩ͢Ͱ
    (Ұൠతʹ͸)࠷ߴͷ'8Ͱ͸ͳ͍ɺ೦಄ʹ͓͘͜ͱ

    View Slide

  33. ଞɺαϯϓϧίʔυͷ୳͠ํ
    » GitHubΛͱΓ͋͑ͣݕࡧͯ͠ΈΔ
    » php web frameworkͱ͔Ͱݕࡧ
    » GHʹ͸੕ͷΑ͏ʹɺຖ೔ΦϨΦϨFW͕ര஀ͯ͠
    ͍ΔͷͰ༐ؾ͕༙͘ʂ
    » Ͱ͖Ε͹Star͕ଟͯ͘ɺίʔυ͕ಡΊͦ͏ͳ΋ͷ͕
    Α͍
    » ͱΓ͋͑ͣ৭ʑಈ͔ͯ͠ΈΔ

    View Slide

  34. Tips
    » Commit͕গͳ͍΋ͷ͸஍ཕʢͱ͍͏͔׬੒ͯ͠ͳ͍ʣ
    » υΩϡϝϯτ͕΋ͷ͘͢͝੔උ͞Ε͍ͯΔ΋ͷ͸༻్͕൚༻త͢
    ͗Δ͔΋ʢ༷ʑͳέʔεʹରԠ͢ΔͨΊɺෳࡶͩͬͨΓ͢Δʣ
    » ίϛολʔ͕͘͢͝ଟ͍΋ͷ͸ඍົ
    » ϓϥάΠϯ͕ͳ͍΋ͷ͕Α͍ʢϓϥάΠϯΛ࣮ݱ͢ΔͨΊʹɺෳ
    ࡶͳ͜ͱ͕ଟ͍ʣ
    » ʮ͋Εʹ΋͜Εʹ΋ରԠʂʯ͸ʢίʔυ͕୹͘ͱ΋ʂʣந৅౓
    ͕ߴ͘ɺֶͼ͸͋Δ͕ෳࡶ
    » ૉ௚ʹʮ͜Ε͔͠Ͱ͖·ͤΜʂʯͷ΄͏͕౰વ୯७

    View Slide

  35. ͦͯ͠࡞ऀʹܟҙΛ
    » ଟ͘ͷOSSϥΠηϯε͸ྲྀ༻͕Ͱ͖Δɺ࠷ߴʂ
    » ͨͩ͠ϥΠηϯεʹ͸ै͏͜ͱ
    » MITͳΒAuthor౳ΛͲ͔͜ʹࡌͤΔͳͲ
    » GPL͔Βྲྀ༻͢ΔͳΒɺGPLʹ͢ΔͳͲ
    » ϥΠηϯεهࡌͷͳ͍ϒϩά౳͔Βͷసࡌ͸NG

    View Slide

  36. » ΦϨΦϨͱ͸͍͑FWΛ࡞Δͷ͔ͩΒɺϥΠηϯεʹ
    ͍ͭͯ͸ֶ΅͏
    » ·͋ઈରʹ഑෍͠ͳ͍ͳΒ͍͍͚Ͳɺޙ͔Β୳͢ͷ͸
    େม
    » (ͦͷ΄͏͕ฏ࿨Ͱ͸ʁʁ)
    » ͱΓ͋͑ͣɺྲྀ༻ͨ͠ίʔυͷҾ༻ݩURL͘Β͍ϝ
    Ϟ͓ͬͯ͜͏

    View Slide

  37. Ͱ͸ॳ৺ऀ͕FW੡࡞࣌ʹॻ͘΂͖ΞϓϦͱ͸ʁ
    » ͱ͸ʁ
    » Ұ௨Γͷػೳ͕ඞཁͰ
    » ͱΔ΂͖ڍಈ͕͸͖ͬΓ͍ͯ͠Δ΋ͷ
    » (୯७͔ɺ͓खຊ͕͋Δ΋ͷ)

    View Slide

  38. ೖ໳
    » URL͕index.phpͰ͓ΘΒͳ͍΋ͷ
    » GET,POST͕͋Δ΋ͷ
    » Ϣʔβʔ͕ࣗ༝ͳจࣈΛೖྗͰ͖Δ΋ͷ
    » ʢϑΥʔϜͷʣ֬ೝը໘͕͋Δ΋ͷ
    » ʢϑΥʔϜͷʣϑΟʔϧυʹ੍໿ʢͨͱ͑͹ϝΞυʣ
    ͕͋Δ΋ͷ
    » = ϝʔϧϑΥʔϜʁ

    View Slide

  39. ॳڃ
    » CSRF TokenΛඋ͑Δ΋ͷ
    » HTMLҎ֎ɺJSON౳ΛϨεϙϯεͰ͖Δ΋ͷ
    » ϦμΠϨΫτ͕͋Δ΋ͷ
    » σʔλϕʔεʹಡΈॻ͖ߋ৽͢Δ࢓૊Έ
    » = ܝࣔ൘ʁ

    View Slide

  40. தڃ
    » ϩάΠϯʢSessionʣ͕͋Δ΋ͷ
    » αΠϯΞοϓ͕͋Δ΋ͷ
    » Delete FlagͰͷ࡟আ
    » (Del flag͕ྑ͍ͱݴ͏͜ͱͰ͸ͳ͍ʣ
    » ೚ҙͷΧϥϜͰͷ߱ॱɾঢॱιʔτ
    » N+1తͳɺෳ਺ͷςʔϒϧΛ݁߹͢Δඞཁ͕͋Δ΋ͷ
    » Ϣʔβʔը໘ͱ෼཭͞Εͨ؅ཧը໘͕͋Δ΋ͷ
    » = ձһ੍ܝࣔ൘ʁ

    View Slide

  41. ্ڃ
    » ϑΝΠϧΛΞοϓϩʔυ͢Δ΋ͷ
    » ʢڊେͳɺϝϞϦ͔ΒᷓΕͦ͏ͳʣϑΝΠϧΛμ΢ϯϩʔ
    υ͢Δ΋ͷ
    » ෳ਺ΧϥϜͷΩʔϫʔυݕࡧ
    » ೚ҙͷෳ਺৚݅Ͱͷݕࡧ
    » ૯݅਺͕දࣔ͞Ε͍ͯΔϖʔδϟʔ
    » ACL
    » = (΢ΣϒUIͷ)*OTUBHSBN

    View Slide

  42. ௒্ڃ
    » SNSΈ͍ͨͳҟৗʹେྔͷRoute΍Model͕͋ΔαΠ
    τ
    » ECαΠτΈ͍ͨʹେྔͷϩοΫɾτϥϯβΫγϣ
    ϯɾ֎෦࿈ܞ͕ඞཁͳαΠτ
    » ιγϟήΈ͍ͨʹେྔͷΞΫηε͕ͷ͔͔͠ΓɺΠϕ
    ϯτΈ͍ͨͳେྔͷ୹ظϩδοΫ͕ऻͬͯ͘ΔαΠτ
    » ʢ͜͜·Ͱ͘ΔͱɺٯʹΦϨΦϨϑϨʔϜϫʔΫ͕
    ૿͑࢝ΊΔ…ʣ

    View Slide

  43. େମ͜͜Β΁ΜΛ·ͱΊΔͱ
    » ௒ॳ৺ऀ͸ϩάΠϯͳ͠ͷܝࣔ൘
    » தɾ্ڃڃऀ͸Instagram΋Ͳ͖Λ࡞Δͱྑ͍ͱࢥ
    ͍·͢
    » ͋ͳͨ͸FWͳ͠ͰͲ͜·Ͱॻ͚·͔͢ʁ
    » ॻ͚ͳ͍ʁ͡Ό͋وํʹ͸࣮Γ͕༗ΔνϟϨϯδ
    ʹͳΓͦ͏ʂ

    View Slide

  44. ΦϨΦϨFWͱηΩϡϦςΟʹ͍ͭͯ
    » ΦϨΦϨ͔ͩΒͱආ͚ͯ௨Δ΂͖Ͱ͸ͳ͍
    » ݹ͍FWͰΑ͋ͬͨ͘ϠόΠྫ
    » ύϥϝʔλΛͦͷ··ม਺ʹల։͢Δͱศརʂ
    » Ϣʔβʔͷೖྗ͸֬ೝը໘ͰνΣοΫͨ͠͠ɺhiddenΛͦͷ··Ϟ
    σϧʹ͍ΕΕ͹ศརʂ
    » อଘ͢Δςʔϒϧ໊ΛϢʔβʔೖྗ͔Βϓϧμ΢ϯͰબϕΔ͚Ͳɺϓ
    ϧμ΢ϯͰબ୒ࢶݻఆ͔ͩΒSQL૊Έཱͯʹ͔ͭ͑͹ศརʂ
    » URL͔ΒΫϥε΍ϝιου໊ΛҾͬுΕΔͱϧʔλʔෆཁͰศརʂ
    » ௕ظؒɺߏ଄Խ͞Ε໊ͨલ΍ΞΠίϯ౳ͷϩάΠϯ৘ใ഑ྻΛอଘ͠
    ͍͚ͨͲserialize()Ͱจࣈྻʹͯ͠Cookieʹ͍ΕΔͱศརʂ

    View Slide

  45. » ݹ͍ίʔυ͸ ౰࣌͸ΞϦͩͬͨ ϠόΠίʔυ͕͍ͬͺ
    ͍ɺਅࣅΔͱةݥ
    » Ͱ΋ɺʮ͜ͷίʔυ͸ةݥʯͱ͔Θ͔Βͳ͍͓…
    » ݹ͍ઃܭ͚ͩͲόʔδϣϯ͕ͪΌΜͱ্͕͍ͬͯΔ
    FWΛਅࣅ͠Α͏ʢ͋Δͷ͔ʁʣ
    » ษڧ͠·͠ΐ͏
    » ಙؙຊ
    » աڈͷCVEΛͲΜͲΜಡΉ
    » (େม͚ͩͲ࣮ྫ͕ͲΜͲΜΘ͔Δ͠ɺલޙͷVerUpΛ
    ୳Ε͹࣮ࡍͷରࡦίʔυ͕Έ͔ͭΓɺ͓͢͢Ί)

    View Slide

  46. ΍͍͖ͬͯ·͠ΐ͏
    » ܝࣔ൘͘Β͍ͳΒɺ๺ւಓͷτʔΫΛݟ͍ͯͩ͘͞
    ʢ͕࣌ؒ଍Γ͵ʣ
    » ʮPHPerਓੜɺҰ౓͸ϑϨʔϜϫʔΫΛ࡞͓ͬͯ͜
    ͏ʂʯ
    » https://speakerdeck.com/uzulla/phperren-
    sheng-du-hahuremuwakuwozuo-tuteokou

    View Slide

  47. ͱ͍͏͜ͱͰɺ࣮ྫʢʁʣ঺հ
    » ࠷ԶʹΑΔɺԶͷͨΊͷฏ੒࠷ޙͷΦϨΦϨϑϨʔ
    ϜϫʔΫͷ͝঺հ͢ΔΑʂʂ
    » ʢޙͰࢿྉ͸UL͢ΔͷͰɺ੎͍ྑ͘ߦ͖·͢ʣ
    » ॳ৺ऀ޲͚ͬΆ͘ͳ͍࿩͕ଓ͖·͢ʂ͝ΊΜͳ͍͞ʂ

    View Slide

  48. ܯࠂ
    » ओ؍͕ଟ͍
    » ࢲ͸ࢲͷ՝୊͔͠ߟ͍͑ͯͳ͍
    » ͋ͳͨ΋ओ؍Λ΋ͬͯ͑͑Μ΍Ͱʂͱ͍͏͜ͱͰ
    ͢
    » Τϯλϝͱͯ͠ݟ͍ͯͩ͘͞ʂ

    View Slide

  49. ݸਓతͳಈػ
    » ΊͪΌΊͪΌେख͔ɺϕϯνϟʔΈ͍ͨͳॴͷ࢓ࣄ͕
    ଟ͍
    » ༧ࢉʹγϏΞɺνʔϜͰͷೳྗࠩ͸ܹ͍͠
    » ͔͠͠ଟ͘ͷ৔߹ɺܧଓͯ͠։ൃ͢Δ͜ͱ΋গͳ͍
    » ͢͹΍͘ܖ໿ऴྃɾΫϏʹͳΔ
    » ͦͷޙɺεϙοτґཔ͕ଟ͍
    » ͔͠͠ɺΞϓϦͷ໋͸݁ߏ௕͍

    View Slide

  50. ਺೥ޙʹ͘Δʮ͜Ε௚ͯ͠ʯ
    » ফඅ੫͕ɺ೥߸͕͔ΘΓ·ͨ͠ʙ
    » ݸਓ৘ใอޢ๏͕͔ΘΓ·ͨ͠ʙ
    » ܾࡁձࣾΛม͑·ͨ͠ʙ
    » αʔόʔҠసͯ͠PHPόʔδϣϯ୅ΘΓ·ͨ͠ʙ
    » S3ͷೝূ͕ʙ
    » APIΛ͸΍͍ͨ͠ΜͰ͢ʙ
    » ޙ೚͕ʹ͛·ͨ͠ʙ
    » (૬ख΋࢓ํͳ͘΍Β͟ΔΛಘͳ͍मਖ਼΋ଟ͍

    View Slide

  51. ηΩϡϦςΟରԠ
    » ಥવग़ΔFWͷCVE
    » ʢ͓٬͕ʣίετΛ෷͑ͳ͍
    » ͜Ε͕ʮᘥᙪʯ͔ͰᎍΊΔͭΒ͍ʂ
    » ʮFWબఆʹΑΔ੹೚ʯ͕໰ΘΕΔ͜ͱ΋

    View Slide

  52. » ηΩϡϦςΟקࠂʹରԠ͢Δࣄ͕ʮηΩϡϦςΟʯͰ
    ͸ͳ͍…͕…ཁٻͱͯ͠͸ͦ͏ͳΓ͕ͪ
    » ͳ͓ʮബ͍ϑϨʔϜϫʔΫʯͩͱɺΞϓσͰ͖Δ
    ࣄ͕ଟ͍͕ͦΕ͸ηΩϡΞͱΠίʔϧͰ͸ͳ͍
    » ࢓ํͳ͘ύον΍ϫʔΫΞϥ΢ϯυΛೖΕΔ
    » ϑϨʔϜϫʔΫʹϫʔΫΞϥ΢ϯυΛೖΕΔͱߦ
    ͖ࢭ·Γ
    » Ϗδωεʹ͓͍ͯ͜ͷίετΛʮݟࠐΉʯ͔ɺʮආ͚
    Δʯඞཁ͕͋Δɻ

    View Slide

  53. ྑ͍ϑϨʔϜϫʔΫͰղܾ͠ͳ͍ʂ
    » ςετͱɺςετ͕ݱ࣮తʹͰ͖Δਖ਼ؾͳઃܭ͕ॏཁ
    » FWͰϨʔϧ͔ΒམͪΔͷ͸؆୯
    » ʮύϫʔϓϨΠʯͰʮҟৗͳཁ݅ʢओ؍ʣʯ͕͸͍Δ
    ͱɺͲΜͳϑϨʔϜϫʔΫͰ΋ऴΘΓ
    » ʮϥϐουʹߦ͚ΔʯFW΋ɺݱ৔ͰϥϐουΛڧ੍
    ͞Ε͚ͭͮΔͱૣ൩ϥϐουʹ͍͚ͳ͘ͳΓ͕ͪ

    View Slide

  54. ࡢࠓͷଟ༷ͳ؀ڥ΁ͷରԠ
    » όον΍ɺLambdaɺSwooleɾReactPHPΈ͍ͨͳมΘ࣮ͬͨߦ
    ؀ڥ
    » άάΔͱͰͯ͘Δɺී௨ͷFWͱͭͳ͙ʮΞμϓλʯͱ͍͏΍ͭ
    ͸
    » ORM΍ίϯϑΟάɺDI͕࿩Λ΍΍͕ͪ͘͜͠͠
    » ʮFW͔Β੾Γग़ͤ·͢Αʈʈʯʮ৴͡ͳ͍Αʂʯ
    » ʮ͏·͚͍ͤͬ͘͢Ε͹͍ͩ͡ΐ͏Ϳʯ͚ͩͲFWͷҙຯ͕ബ
    ͘ͳΔ
    » POPOʢPlain old PHP ObjectʣͩͱେମͲ͜ʹͰ΋͍͚࣋ͬͯΔ

    View Slide

  55. ݸਓతͳ೰Έ·ͱΊ
    » ʮ̍Օॴ͔͑Ε͹ɺશ෦มΘΔʯΑ͘Ͱ͖ͨ'8͸࠷
    ߴ
    » ͔͠͠ɺ೥୯ҐͰ͸όʔδϣϯΞοϓ͕ඞཁʢओ
    ؍ʣ
    » εϙοτ࡞ۀ͹͔ΓͰʮܧଓ͠ ͓͕ͯۚ΋Β͑ ͳ
    ͍ʯҊ݅Ͱ์ஔ͞ΕΔͱ٧Ή
    » ʮయܕతͳFWʯʹ൓߅͍͓ͨ͠೥ࠒʂ

    View Slide

  56. » (Ұ෦ͷҊ݅Ͱ)FW΁ͷఘΊ
    » ڋ൱͍ͨ͠Θ͚Ͱ͸ͳ͍͕ɺൣғΛݮΒ͔͢ʁ
    » ͔ͦ͠͠ΕͰ͸FWͷҙ͕ٛ…
    » …Α͠ɺΦϨΦϨ͔ͳʂʢ࿦ཧͷඈ༂ʣ
    » (͜Ε͸ੈͷதͷΦϨΦϨFWͭ͘Δਓؒͷయܕత
    ͳݴ͍༁Ͱ͢ɻಉ྅͕͜͏͍͏͜ͱΛݴ͍ग़ͨ͠
    ΒԥͬͯࢭΊ·͠ΐ͏)
    » (ಉ྅Ͱͳ͍ͳΒ(ྫ͑͹๻͕ݴ͍ग़ͨ͠Β)ɺͦͬ
    ͱ۪ஒΛฉ͍͍ͯ͋͛ͯͩ͘͞)

    View Slide

  57. Α͠…
    » ʮ̍Օॴม͑Ε͹શ෦มΘΔʯ
    » ʮߴ͍ੜ࢈ੑʯ
    » ʮݟ௨͠ͷྑ͍ίʔυʯ
    » Λ࣮ݱ͢Δૉఢͳຐ๏Λࣺͯͯ…
    » ෺ཧͰΰϦԡ͠Ͱઓ͏ͧʂʂʂ

    View Slide

  58. ͱ͍͏͜ͱͰΦϨΦϨϑϨʔϜϫʔΫΛ࡞Δͧʂ
    » ͋͘·Ͱ΋ݸਓతͳײ૝Ͱɺօ༷͸ͦ͏Ͱ͸ͳ͍͔
    ΋͠Εͳ͍ɻ
    » ʢτʔΫͷྲྀΕ্ɺ͜͜͸ೲಘ͍ͩ͘͞ʣ
    » ʮͳΜͰ͋ΕɺΦϨΦϨ͸ͳ͍ͩΖʯͱ͍͏ͷ͸ਖ਼
    ؾͳҙݟͰ͢ʢࢲ΋ී௨ʹී௨ͷϑϨʔϜϫʔΫ΋
    ࢖͍·͢ʣ
    ͥͻͦͷ··͓͍࣋ͪͩ͘͞

    View Slide

  59. Ore3 FW
    » https://github.com/uzulla/Ore3
    » (Ore1,2͸લ࡞ͬͨͷͰ(҆қ))
    » ༻్ɺJSON API
    » ໨ࢦ͢ॴ
    » ΤϥʔϋϯυϦϯά
    » ୯७͞
    » αόΠϒੑʢओ؍
    » ςετ͠΍͢͞

    View Slide

  60. ʮαόΠϒʯͱ͸ʁ
    » Ͱ͖Ε͹ɺ<৽ݩ߸>5೥Ͱ΋ɺͪΐͬͱͷमਖ਼Ͱಈ͘
    » ՄೳͳΒɺฏ੒ͷϥΠϒϥϦΛࢥ͍ग़͞ͳͯ͘ࡁΉ
    » ئΘ͘͹ɺ͔ͦ͜Βյͣ͞ʹमਖ਼Ͱ͖Δ
    » ख͕͔͔ؒͬͯ΋ɺ95%ͷέʔεͰ޻਺͕ಡΈ΍͢
    ͍ɺϋϚΒͳ͍
    » ։ൃதͷ࢓༷ύϫʔϓϨΠʹରԠͰ͖Δ

    View Slide

  61. ࠓճͷΦϨΦϨFWʹ͓͚Δࡦ
    » ʮίʔυͷ֎ʯʹཔΔ͕ɺੜ੒͸͠ͳ͍
    » *%&ͳͲπʔϧͷαϙʔτʢิ׬ɺ੩తղੳɺϦϑΝΫλػೳʣ
    Λ࠷େݶʹड͚ΒΕΔΑ͏ʹ
    » ੩తղੳ(ྫ:IDEͷInspect Code)ͷ׆༻
    » ૉ๿ͳςετͷίετΛԼ͛Δ
    » ๨Εͯ΋͓͍͔͚ΒΕΔΑ͏ʹ
    » ҉໧ͷίʔυΛ΁Β͢(഑ྻΛҾ͖ճ͞ͳ͍ɺΫϥε΍ϓϩύςΟ
    Λ࡞Δ)
    » VCSͱͷ਌࿨ੑΛ্͛Δ(#MBNF͠΍͘͢ɺ%J⒎ΛΈ΍͘͢ ओ؍
    )

    View Slide

  62. ʮٯʹIDE౳ͷπʔϧͷຐ๏ʹཔͬͯͳ͍͔ʁʯ
    » ࠓޙIDEʢ΍PHPͷ੍໿ʣ͕؇Ήํ޲ʹਐ·ͳ͍ࣄʹ
    ౌ͚͍ͯΔ
    » ʮ…͜ΕPHPUnit͔ͭͬͯΔΑͶʁʯʮ΢οʯ

    View Slide

  63. ࠓճ࡞ͬͨػೳ
    » ϧʔλʔ
    » Ϗϡʔ
    » ORM
    » DI

    View Slide

  64. ࠓճ࡞ͬͨػೳʂ
    » ϧʔλʔ ͳ͠
    !
    » Ϗϡʔ ͳ͠
    !
    » ORM ͳ͠
    !
    » DI ͳ͠
    !

    View Slide

  65. ࣮૷ͨ͠ػೳ͸
    » ϦΫΤετ/Ϩεϙϯε ΦϒδΣΫτ
    » େҬͳΤϥʔϋϯυϦϯά

    View Slide

  66. ͓࡞๏(ػೳͰ͸ͳ͍)
    » ϦΫΤετɺϨεϙϯεͷ࡞๏
    » σʔλɾϞσϧपΓͷ͓࡞๏

    View Slide

  67. ϑΝΠϧߏ଄
    !"" composer.json
    !"" api_real.php
    !"" shell.php
    !"" lib
    # $"" MyApp
    # !"" Api
    # # !"" Action
    # # !"" Request
    # # $"" Response
    # !"" Model
    # !"" Repo
    # $"" Service
    $"" tests
    # $"" testTest.php
    $"" vendor

    View Slide

  68. !"" composer.json
    !"" api_real.php
    !"
    !"" shell.php
    !"" lib
    # $"" MyApp
    # !"" Api
    # # !"" Action
    # # !"" Request
    # # $"" Response
    # !"" Model
    # !"" Repo
    # $"" Service
    $"" tests
    # $"" testTest.php
    $"" vendor

    View Slide

  69. api_realͷྲྀΕ
    » 0. Τϥʔϋϯυϥొ࿥
    » 1. σΟεύον
    » 2. ϦΫΤετΦϒδΣΫτੜ੒(*Request.php)
    » 3. ΞΫγϣϯ࣮ߦ(*Action.php)
    » 4. (ΞΫγϣϯͷதͰ)ϨεϙϯεΦϒδΣΫτੜ
    ੒(*Response.php)
    » 5. ϨεϙϯεΦϒδΣΫτΛૹ৴

    View Slide

  70. ୯७Խͨ͠΋ͷ
    set_error_handler(/* ... */); // 0. Τϥʔϋϯυϥ
    try{
    if($_SERVER['REQUEST_URI']='/'){ // 1. σΟεύν
    $req = new SomeRequest($_POST); // 2. reqੜ੒
    $res = SomeAction::run($req); // 3. resੜ੒
    }else{ /* ... */ }
    }
    // $res 4. Ϩεϙϯε
    $res->writeHeader($http_origin_header); // 5. ૹ৴
    $res->writeBody();// 5. ૹ৴

    View Slide

  71. 0. Τϥʔϋϯυϥઃఆ౳-1 (গʑ؆ུԽͯ͠·͢
    set_error_handler(function ($severity, $message, $file, $line) {
    throw new ErrorException($message, 0, $severity, $file, $line);
    });
    register_shutdown_function(function () {
    $error = error_get_last();
    if (!is_array($error) || !($error['type'] &
    (E_ERROR|E_PARSE|E_USER_ERROR|E_RECOVERABLE_ERROR))) { return; } // ਖ਼ৗऴྃܥ
    error_log("Uncaught Error: ..."); // Ωϟονͨ͠ΤϥʔΛϩά
    http_response_code(500); // response error
    header("Content-type: application/json");
    echo json_encode([ "code" => 500,
    "message" => "internal server error" ]);
    }); // ࣍ͷεϥΠυʹଓ͘

    View Slide

  72. 0. Τϥʔϋϯυϥઃఆ౳-2 (গʑ؆ུԽͯ͠·͢
    try { //લͷεϥΠυ͔Βଓ͘
    ob_start();
    require(__DIR__ . "/vendor/autoload.php");
    // =========

    ͜͜ʹΞϓϦίʔυ

    =============
    ob_end_flush();
    } catch (\Throwable $e) { // Uncaught Exception
    $error_class_name = get_class($e);
    error_log("Uncaught Exception {$error_class_name}: ..."); // ྫ֎Λϩά
    http_response_code(500); // response error
    header("Content-type: application/json");
    echo json_encode([ "code" => 500,
    "message" => "internal server error" ]);
    }

    View Slide

  73. » ϋϯυϥΛ࠷ॳʹઃఆ͠ɺNotice΋Warning΋
    Ωϟονͯ͠ϩάˍΤϥʔը໘
    » ΞϓϦશମ΋tryͰ͘͘ΓɺΩϟονͯ͠ϩάˍΤ
    ϥʔը໘
    » ͜Ε͘Β͍΍Δͱศར
    » ͜ΕΛઆ໌͢Δͱ௕͘ͳΓ͗͢Δ…ͷͰলུ
    » ʢͦͷ͏ͪͲ͔͜Ͱ͜ͷ࿩͸͍ͨ͠Ͱ͢Ͷʣ

    View Slide

  74. Output bufferͰ༧ظͤ͵ग़ྗΛ཈੍
    ob_start();// Output bufferingΛ։࢝
    $res = MyApp(); // ͜͜Ͱ͸ͳʹ΋ग़ྗ͠ͳ͍ɺ͋ͬͨΒΤϥʔ͔Կ͔
    $something = ob_get_contents(); // ҙਤ͠ͳ͍ग़ྗ͕͋ͬͨΒϩά΁
    if (strlen($something) > 0) {
    error_log($something);
    }
    ob_end_clean(); // (্Ͱϩάʹग़͍ͯ͠ΔͷͰɺࣺͯΔ)
    ob_start(); // ͔͜͜Β࣮ࡍʹૹ৴
    $res->writeHeader($http_origin_header);
    $res->writeBody();
    ob_end_flush();

    View Slide

  75. » obଟ༻ͷ໨త͸
    » ʮΤϥʔ࣌ʹ่Εͨग़ྗΛͩ͞ͳ͍͜ͱʯ
    » ʮ૝ఆ͍ͯ͠ͳ͍ग़ྗΛޡͬͯग़͞ͳ͍͜ͱʯ
    » ʮޡͬͯ200Λฦ͞ͳ͍͜ͱʯ
    » PHP͸ɺΤϥʔ౳Ͱ༧ظͤ͵ग़ྗ͕ग़Δͱૹ৴͞Εͯ͠·
    ͏ɺ͢Δͱϔομʔ΋ૹΕͳ͍ɺ͜Ε͸Web APIͩͱඍົ
    » ͳͷͰɺϨεϙϯεΦϒδΣΫτͰͷૹ৴Ҏ֎͸ɺશ෦ྫ
    ֎తͳ΋ͷͱͯ͠obͰ֬อͯ͠ϩάߦ͖ʹ͢Δɻ
    » var_dump()͕print debugͰ࢖͑Δͧʂศརʂ

    View Slide

  76. ࠶ܝࡌʣ୯७Խͨ͠΋ͷ
    set_error_handler(/* ... */);
    try{
    if($_SERVER['REQUEST_URI']='/'){
    $req = new SomeRequest($_POST);
    $res = SomeAction::run($re
    }else{ /* ... */ }
    }
    $res->writeHeader($http_origin_header);
    $res->writeBody();

    View Slide

  77. 1. σΟεύονͱ͍͏໊લͷifจ
    $request_uri = $_SERVER['REQUEST_URI'];
    $method = $_SERVER['REQUEST_METHOD'];
    $http_origin_header = $_SERVER["HTTP_ORIGIN"] ?? null;
    $base_uri = "/api";
    $path = substr($request_uri, strlen($base_uri));
    $path = explode("?", $path, 2)[0];
    if ($method === "OPTIONS" && !is_null($http_origin_header)) {
    $res = new \MyApp\Api\Response\CORSPreFlightResponse();
    } else if ($method === "GET" && $path === "/hello") {
    $req = new \MyApp\Api\Request\HelloRequest($_GET);
    $res = \MyApp\Api\Action\HelloAction::run($req);
    } else {
    $res = new \MyApp\Api\Response\Response();
    $res->code = 404;
    }

    View Slide

  78. » ʮ̎̌೥લ͔ͳʁʯ
    ʮύεύϥϝʔλΛ࢖Θͳ͚Ε͹͑͑Μ΍ʯ
    » ʢRESTfulͷ͜ͱΛߟ͍͑ͯͳ͍ʣ
    » ඞཁʹͳΕ͹ϧʔλʔΛೖΕΕ͹͍͍Ͱ͠ΐ
    » ʮpreg_matchͰ΋࣮ݱͰ͖ΔͰ͠ΐʢʁʁʯ
    » ྑ͍ϧʔλʔΛ͍Εͯ΋ɺେ఍ଟػೳΛ࢖Θͳ͍…
    » ελοΫτϨʔε͕ബ͍ʢϩά͕ݟ΍͍͢ʣ
    » ಥવݱΕͨ୹ظతͳṖ࢓༷ͷ૬ख͕Ͱ͖ΔɺϦΫΤε
    τΛ٧Ίସ͑ͯ͠ΞΫγϣϯΛίʔϧ͢Δͱ͔

    View Slide

  79. ࠶ܝࡌʣ୯७Խͨ͠΋ͷ
    set_error_handler(/* ... */); // 0. Τϥʔϋϯυϥ
    try{
    if($_SERVER['REQUEST_URI']='/'){ // 1. σΟεύν
    $req = new SomeRequest($_POST); //
    $res = SomeAction::run($req); // 3. resੜ੒
    }else{ /* ... */ }
    }
    // $res 4. Ϩεϙϯε
    $res->writeHeader($http_origin_header); // 5. ૹ৴
    $res->writeBody();// 5. ૹ৴

    View Slide

  80. !"" composer.json
    !"" api_real.php
    !"" shell.php
    !"" lib
    # $"" MyApp
    # !"" Api
    # # !"" Action
    # # !"" Request
    !"
    # # $"" Response
    # !"" Model
    # !"" Repo
    # $"" Service
    $"" tests
    # $"" testTest.php
    $"" vendor

    View Slide

  81. 2. ϦΫΤετΦϒδΣΫτ
    class HelloRequest extends Request implements RequestInterface {
    use ValidateRegexTrait;
    public $name;
    public function __construct(array $list)
    {
    $el = [];
    $result = $this->validateWithRegex($el, $list, 'name', "/\A[a-zA-Z0-9]{1,32}\z/u", true);
    $el = $result->error_list;
    $this->name = $result->val;
    $this->_error_list = $el;
    }
    }

    View Slide

  82. » جຊ1ϧʔτʹ͖ͭɺ1Ϋϥε
    » ίϯετϥΫλʹ഑ྻ($_POST,$_COOKIE౳ʣΛ౉͢
    » εʔύʔάϩʔόϧ͸ɺ͜ͷޙ͸Ұ੾࢖Θ͵੤͍
    » ςετ࣌ʹָˍͦΕ͕ͳ͍ಛघ؀ڥͱͭͳ͗΍͘͢
    » Ϋϥε͸༧ఆ͞ΕΔύϥϝλ෼ͷϓϩύςΟม਺Λ࣋ͭ
    » ϗϫΠτϦετͰ໌ࣔత
    » ޙड़ͷΞΫγϣϯ͸ɺϓϩύςΟม਺Λ௚઀৮Δ
    » *%&Ͱิ׬ɾ*OTQFDU͠΍͍͢
    » ΧϓηϧԽ͕໨తͰ͸ͳ͍ͷͰpublic
    » ̍ʙׂ̎Ͱ࢖ΘΕΔϝιου͸ɺܧঝͰͳ͘Trait

    View Slide

  83. !"" composer.json
    !"" api_real.php
    !"" shell.php
    !"" lib
    # $"" MyApp
    # !"" Api
    # # !"" Action
    !"
    # # !"" Request
    # # $"" Response
    # !"" Model
    # !"" Repo
    # $"" Service
    $"" tests
    # $"" testTest.php
    $"" vendor

    View Slide

  84. 3. ΞΫγϣϯ
    class HelloAction
    {
    public static function run(HelloRequest $req): ResponseInterface
    {
    if (!$req->isValid()) {
    return new ErrorResponse($req, 400, "bad request", $req->getErrorList());
    }
    $name_san = NameSanService::getByName($req->name);
    return new HelloSuccessResponse($name_san);
    }
    }

    View Slide

  85. » ͍ΘΏΔίϯτϩʔϥʔɺ੩తͳϝιουͰΑ͍
    » Ҿ਺͸ϦΫΤετΦϒδΣΫτ
    » ฦΓ஋͸ResponseInterfaceΛ࣮૷ͨ͠΋ͷ
    » ޙड़ͷServiceΛୟ͖·͘ΓɺϨεϙϯεΛ࡞Δ

    View Slide

  86. ࠶ܝࡌʣ୯७Խͨ͠΋ͷ
    set_error_handler(/* ... */);
    try{
    if($_SERVER['REQUEST_URI']='/'){
    $req = new SomeRequest($_POST);
    $res = SomeAction::run($req); // ͜͜·ͰऴΘͬͨ
    }else{ /* ... */ }
    }
    // $res 4. Ϩεϙϯε
    !
    $res->writeHeader($http_origin_header); // 5. ૹ৴
    $res->writeBody();// 5. ૹ৴

    View Slide

  87. !"" composer.json
    !"" api_real.php
    !"" shell.php
    !"" lib
    # $"" MyApp
    # !"" Api
    # # !"" Action
    # # !"" Request
    # # $"" Response
    !"
    # !"" Model
    # !"" Repo
    # $"" Service
    $"" tests
    # $"" testTest.php
    $"" vendor

    View Slide

  88. 4. Ϩεϙϯε
    class HelloSuccessResponse extends Response implements ResponseInterface {
    public $code = 200;
    public $name_san = null;
    public function __construct(NameSan $name_san)
    {
    $this->code = 200;
    $this->name_san = $name_san;
    }
    public function getBody(): string {
    return json_encode([ 'code' => $this->code,
    'name_with_san' => $this->name_san->name ]);
    }
    public function writeBody(): void {
    echo $this->getBody();
    }
    }

    View Slide

  89. » ϨεϙϯεΦϒδΣΫτ΋ɺίϯετϥΫλͰʮ࣮ࡍʹඞཁͳ
    Ҿ਺ʯΛड͚औΔ
    » ͜͜Ͱ͸εΧϥʔͰ͸ͳ͘ɺϞσϧͷΫϥε໊ͰܕΛࢦఆ͢Δ
    » ϓϩύςΟʢ͜͜Ͱ͸$name_san)ʹ͸ϞσϧͷΠϯελϯε
    ΛೖΕ͓ͯ͘
    » ֤छϞσϧΛϨεϙϯε·Ͱ࣋ͪࠐΉ͓࡞๏ͩͱɺtoArray
    લ͕ݟΕΔͷͰJSONΛ૬खʹจࣈྻςετͤͣʹࡁΉ
    » मਖ਼ൣғ͕ڱ͍ͷͰɺίϛοτϩά͔Β௥͍͔͚΍͍͢
    ʢओ؍ʣ
    » ͜ͷ""ͱ͍͏ۭจࣈྻ్͕தͷΩϟετϛε͔ɺͦ͏Ͱͳ
    ͍͔൑அ͠΍͍͢ɺ౳ɻ

    View Slide

  90. » get/writeBody()Ͱॴఆͷܗʹม׵͢ΔͷΛखͰॻ͘
    » Ϩεϙϯεͷܗ͸Ϟσϧͷߏ଄ʹґଘͤ͞ͳ͍
    » (ఆܗͷdefinitionͷ৔߹ʔͨͱ͑͹UserInfoͱ͔ʔ͸Ͳ͔͜ʹ
    toArray()ͱ͔ϔϧύΛ࡞Δࣄ΋͋Δ)
    » ӡ༻ϑΣʔζʹ͸͍Δͱɺςʔϒϧ͸ม͑ͳ͍͚Ͳݟͤํ͸͔ΘΓ͕ͪ
    » ಥવඇਖ਼نͳΧϥϜ͕૿͑Δ࣌ʹɺϞσϧ΍ActionΛ͍͡Βͳͯ͘
    ΋ResͰٵऩͰ͖Δ
    » ྫɿ͋ΔAPI͚ͩauthor͕CSVͰ΄͍͠ʢ΄͔͸഑ྻͳͷʹ…ʣ
    » ྫɿ͜ͷϨεϙϯε͸Ձ֨ΛӅ͍ͨ͠ɺΫϩʔϧ͞Εͨ͘ͳ͍
    » ʮ͜ͷ࢓༷Ͱ߹ҙ͕ͱΕͨΜͩɺ͔ͩΒே·Ͱʹ࡞ͬͯʯ
    » ͋Δ͍͸ɺϞσϧ͕͔Θͬͯ΋API࢓༷ΛഁյͰ͖ͳ͍

    View Slide

  91. » ͜ͷΫϥεʹૹ৴ʢechoʣ͢Δίʔυ͕͋Δ
    » body͕ڊେͳόΠφϦͳΒɺ͜͜ͰҰ୴obΛ͸ͣ͢
    ͳͲ޻෉͕Ͱ͖Δ
    » ͦͷͨΊɺʮඞཁʹԠͯ͡ʯResʹStream΍
    GeneratorΛΘͨͯ͠Α͍

    View Slide

  92. 4. Ϩεϙϯε(ϔομʔؔ࿈) ؆ུԽͯ͠·͢
    class Response implements ResponseInterface {
    public $code;
    protected $header_list = [ "Content-type" => "application/json" ];
    protected $cookie_list = [];
    public function __construct($code, $name){ $this->code = $code; }
    public function writeHeader(string $http_origin = null): void {
    foreach ($this->getHeader($http_origin) as $key => $val) {
    header(sprintf("%s: %s", $key, $val)); // ϔομૹ৴
    }
    foreach ($this->cookie_list as $cookie) {
    CookieService::setCookie($cookie); // ΫοΩʔૹ৴
    }
    http_response_code($this->code); // Ϩεϙϯείʔυηοτ
    /* ... */

    View Slide

  93. » ϔομʔ΍ΫοΩʔ͸ಉ༷ʹϓϩύςΟʹʢ഑ྻͱ͠
    ͯʣ΋ͭɻ
    » cookieͳΜ͔͸CookieͷϞσϧͰ͸͍͍ͬͯΔ
    » ςετͷͨΊʹ
    » ࣮ࡍʹwriteHeader͢Δ·Ͱ͸ૹ৴͠ͳ͍
    » writeBodyಉ༷ʹɺ௚઀ϔομʔΛૹ৴͢Δίʔυ
    Λ͜͜ʹॻ͘
    » Etag΍TTLͱ͔ɺPrivateɺno-cacheΈ͍ͨͳͷ΋
    ॻ͘

    View Slide

  94. 5. api_realʹ΋Ͳͬͯૹ৴
    set_error_handler(/* ... */);
    try{
    if($_SERVER['REQUEST_URI']='/'){
    $req = new SomeRequest($_POST);
    $res = SomeAction::run($req);
    }else{ /* ... */ }
    }
    $res->writeHeader($http_origin_header); // 5. ૹ৴
    $res->writeBody();// 5. ૹ৴

    View Slide

  95. » ࠷ޙͰResͷwriteHeader/Body͕ݺ͹ΕΔ
    » writeHeader()Ͱϔομʔ(CORSܥ΍Content-
    typeɺExpire΍Attachment)/ΫοΩʔΛૹ৴
    » writeBody()͕σʔλΛૹ৴ʢechoʣ
    » ʢgetBody/Header()͸جຊతʹ͸ςετͷͨΊʹ͋
    ΓɺwriteBody()͔ΒgetBody()΁ͷݺͼग़ؔ͠܎͸
    ڧ੍͠ͳ͍ɺͪΐͬͱ໊෇͚͕ඍົ…ʣ

    View Slide

  96. ͸͍
    » ܕ͕ଟ͍
    » ໌ࣔ
    » %*Λ࢖Θͳ͍

    View Slide

  97. ͭΒ͍ͱ͜Ζʢଞਓͷ૝૾ʣ
    » ίʔυ͕ଟ͍
    » IDEͱͰ͔͍Ϟχλʔਪ঑
    » मਖ਼Օॴ͕ଟ͍
    » ҰൃͰόʔϯʂͬͯͳΒͳ͍
    » IDE͔ͭͬͯͳ͍ͱॻ͖ଛ͕͡ଟ͍
    » ϦϑΝΫλ΋IDE͕ͳ͍ͱͭΒ͍
    » ແ৺Ͱॻ͖׵͑ΔࠜੑϓϨΠ

    View Slide

  98. ଓ͍ͯɺσʔλपΓͷن໿ະ
    ຬɺ͓໿ଋ…͸ࠓճεΩοϓ
    » σʔλͷߏ଄…ͳΜͰ͕͢
    » ͞Βʹॳ৺ऀͷܕ…͍΍ํΛஔ͖ڈΓʹ͢Δಠળ
    తɾಠΓΑ͕Γͳ಺༰
    » 30෼ͷτʔΫͰ͸͓ΘΒΜͷͰεΩοϓ͠·͢ʂ
    ʢ͓ΘΓʹ͚͓͖ͭͯ·͢ʣ
    » ޙͰΈͳ͞ΜࢿྉΛΑΜͰͶʂ

    View Slide

  99. ͸͍

    View Slide

  100. Ore3 ·ͱΊ
    » ੩తղੳπʔϧ͔ΒཧղͰ͖ΔΑ͏ʹ
    » ܕΛՄೳͳݶΓॻ͘
    » DIͳ͠
    » ʮઃఆϑΝΠϧʯ͸࠷খݶʹ
    » ςετͷखؒΛ΁Β͢
    » ೖྗͱग़ྗͷςετΛॻ͖΍͘͢ʢओ؍ʣ
    » PHPຊମͷػೳ͸ૉ௚ʹ͔ͭ͏

    View Slide

  101. » ܽ఺͸΋ͪΖΜमਖ਼ൣғ͕޿͘ͳΔ͜ͱ
    » IDEͱςετͰࠜੑͰ۪௚ʹ࣏͢
    » ςετ΍ܕͰɺ੔߹ੑΛ୲อ͍ͯ͘͠
    » ʮ͜ΕFWͷҙຯ͋Δʁʯ
    » ͔͠͠मਖ਼࣌ؒΛݟੵ΋Γ͠΍͍͢ʢओ؍ʣ
    » 90%ͷཁ݅Λ̍࣌ؒͰ௚ͤΔ୅ΘΓʹ10%Ͱ͸ϋϚͬͯҰि
    ͔͔ؒΔΑΓɺ95%͕̍ప໷ͰऴΘͬͯ΄͍͠ʢओ؍ʣ
    » ಥવJOINͱ͔UNIONඞཁʹͳΔͱORMΉ͔ͣ͗ͯ͢͠
    ʮSQL͔͔ͤͯ͘ΕʂʂʯͱͳΔʢษڧෆ଍ʣ
    » ORMͷΉ͔͍ͣ͠࢖͍ํ͸๨Ε͕ͪɺSQLͩͱ͙͢ʹΘ͔
    Δ…ʢ࿝ਓʣ

    View Slide

  102. » ʮδϟόͰ͍͍ͷͰ͸ʁʯʮsorry, I am PHPerʯ
    » ʮhackͰ͍͍ͷͰ͸ʁʯʮhackʹPHPStorm΄͠
    ͍ʯ
    » Typed Properties͖ͯ΄͍͠ʂࠓ͙͢ʂ
    » Enum͖ͯ΄͍͠ʂࠓ͙͢ʂ
    » listड͚͍ͨ͠ʂδΣωϦΫεʂ
    » (େମ͜͏͍͏ͷHackʹ͋ΔΜͩΑͳΝ)
    » ·͋ɺࢲ͸PHPerͳͷͰ

    View Slide

  103. » ͍ͩͿʮࣗݾத৺తʯͰ͢ͶɺΦϨΦϨײ͋Δʂʂ

    View Slide

  104. ݁ՌɺͲ͏ͳ͔ͬͨʁʢϑΟ
    ΫγϣϯͰ͢
    » ʮࢲ͸ʯ޻਺͕ΑΊΔΑ͏ʹͳͬͨ(ओ؍)
    » IDE͕͋Ε͹ɺ(ςετ͢Δ·Ͱ΋ͳ͘)suspectsͰׂ
    ͷϛεʹؾ͚ͮΔΑ͏ʹ
    » (IDE΍ςετΛ͠ͳ͍ਓͱ΍Δͱ)ίʔυमਖ਼ɾϨ
    Ϗϡʔෛՙ্ঢ
    » ·͋ɺࢲ͕੹೚ͱΔʢ؃औΔʣҊ݅ͳͷͰେৎ෉(?)

    View Slide

  105. ٘ਜ਼͸ͳʹ͔ʁ
    » ଞਓ͔Βݟͨʮ͓͠ΌΕʯ͞
    » ʢΧʔΰɾΧϧτΛ৴͡Δʣࣗ෼ͷࣾձੑ
    » ̍ՕॴΛม͑Δͱશ෦͕׬੒͢ΔΑ͏ͳମݧ
    » ػցʢIDEʣʹͨΑΒͳ͚Ε͹ಡΊͳ͍
    » ػցʢςετʣʹͨΑΒͳ͚Ε͹݈શ͔Θ͔Βͳ͍

    View Slide

  106. ͸͍

    View Slide

  107. ͜Ε͸FWͳͷ͔ʁ
    » ͜Μͳػೳ͕͘͢ͳ͍͍ͯ͘ͷ͔ʁ
    » ͍΍͍΍ɺࢲʹ͸͜Ε͸FWͰ͢Α
    » ίʔυͷଟՉ͕FW͔Ͳ͏͔Ͱ͸ͳ͍ʢ̍πΠʔτ
    ʹೖΔFWͳͲ͋ΔΘ͚Ͱʣ
    » FWͱ͸ίʔυͷ࣮ମͰ͸ͳ͍ʂελΠϧͰ͋
    Δʂʢओ؍

    View Slide

  108. ͱ͍͏͜ͱͰΦϨΦϨFWͷ
    ঺հͰͨ͠ʂ
    » ੈքͷย۱ʹ͸͜͏͍͏ߟ͑ํ΋͋Δʂ

    View Slide

  109. ॳ৺ऀ޲͚·ͱΊ
    » FW࡞Δͷ͸ͨͷ͍͠ʂͰ΋ͦͷखؒͰΞϓϦ͕࡞ΕΔ
    ͧʂʂʂ
    » ࡞Δ΋ͷ͕ʰੈͷதͷ80%ͷ΢ΣϒΞϓϦʱͳΒɺͨ͠
    ͔ʹʰ80%ʹ޲͍͍ͯΔϑϨʔϜϫʔΫʱΛ࢖͏΂͖
    » ΦϨΦϨ͸ࣗ෼ࣗ৴΍<৽ݩ߸>ʹjoinͨ͠νʔϜϝΠ
    τʹ࠘·ΕΔͧʂʂ
    » झຯͷൣғʹ͠·͠ΐ͏
    » ʮ࢖͍ํʯҎ֎΋ֶ΅͏

    View Slide

  110. தڃऀ޲͚·ͱΊ
    » ͝ଘ஌ͷ௨Γ(?)ʮϝδϟʔͳFWΛ͔ͭͬͨΒສࣄղܾʯ͠ͳ͍͕ɺ
    ਏͯ͘΋͕Μ͹Δͷ͕ਖ਼͍͠ಓͩ
    » ͢Ͱʹ͋Δ஌ݟɾઃܭɾϥΠϒϥϦΛ୳͠ɺֶ΅͏
    » ͨͩɺڝ߹ͱಉ͡Ͱڝ૪ͰউͯΔͷ͔ʁ
    » FWΛʮ৐Γ׵͑Δʯͱ͍͏ߦҝࣗମ͕͔ͳΓܦݧ͕ͨ·ΔͷͰἚͷ
    ಓΛΏ͜͏
    » ΦϨΦϨFW͔Β୤٫Ͱ͖Δɺ͋Δ͍͸ΦϨΦϨFWʹҠߦͰ͖Δ
    ઃܭ
    » ʮࠓͲ͖͸͜Εͩʂʯͱ͔ࣖ೥૿ʹͳΔͱɺPHPerϥΠϑͷָ͠͞
    ͕൒ݮͯ͠͠·͏ͧʂΈΜͳΦϨΦϨͯ͠Δʂ܅΋ΦϨΦϨ͠Α͏ʂ

    View Slide

  111. ্ڃऀ޲͚·ͱΊ
    » ʮ͜Μͳ͜ͱ͍ͬͯΔ͚ͲΦϨΦϨ͕̑೥͔࣋ͭʁʯ
    ʮͦΕͳʯ
    » ୤ग़͸ݟࠐΜͰ͓͔͘͠ͳ͍͠ɺͦͷͨΊʹ͸ۃྗ
    ෼཭Մೳʹ͠ɺγϯϓϧʹ͍͖͍ͯͨ͠
    » Ҡॅ͕Ͱ͖ΔͳΒɺͲΜͳFWͰ΋ɺΦϨΦϨͰ΋͓
    ͦΔΔʹ଍Βͣʢͦ͏͔ʁʁʣ
    » ࢲ৴ɿΠέͯΔSQLBuilderΛ͕͚͍ͭͮͯ͞͠·͢

    View Slide

  112. ·ͱΊ
    » ʮϚδϣϦςΟʢʁʣʯΛ໡৴ͯ͠·ͤΜ͔ʁ
    » ׳ྫΛٙ͏ͷ͸ॏཁ
    » ʢതଧͱͯ͠͸ɺϚδϣϦςΟͷํ͕҆ṛ͚ͩͲʂʣ
    » ʮ͍͍͜ͱݴͬͯΔʯ෩ͳҙݟΛ৴͡Δͳʢʁʁʁ
    » #΍ͬͯΈΑ͏ͥ
    » ͱ͍͏͜ͱͰɺΈΜͳ ࣗ͝୐Ͱ
    ΦϨΦϨϑϨʔϜϫʔ
    ΫΛ͍ͭͬͯ͘͜͏ͳʂʂΦϨʹ΋Έͤͯ͘Εʂʂ

    View Slide

  113. ׬

    View Slide

  114. ܁Γฦ͠
    » #ΦϨΦϨϑϨʔϜϫʔΫ
    ͸·ͣ͸झຯͰ΍Ζ͏ͳʂʂ

    View Slide

  115. ʮͳͥPSR-7(౳)Ͱ͸ͳ͍ͷ͔ʁʯ
    ʮͳͥReq/ResΛ࠶ൃ໌ͨ͠ͷ͔ʁʯ
    » ݁ߏ࢖ͬͨΜͰ͚͢Ͳ…ίʔυ͕௕͘ͳΓ͕ͪʂςετਏ͍
    » psr7͸http༻ͳͷͰɺࠓࣗ෼͕΄͍͠΋ͷΑΓϩʔϨϕϧ
    » ·ͩࢫຯ͕গͳ͍ʂ
    » ·͋ɺpsr7͕ඞཁʹͳΕ͹Ξμϓλॻ͚Δ
    » Req/ResͰܕΛ͠͹Γ͍ͨཉ͕͋ͬͨ
    » psr7Λجఈʹ֦ͯ͠ுͮ͠Β͗͢ΔͰ͠ΐ…
    » ࢓༷ύϫʔϓϨΠରॲͷ୤ग़ϋονΛ࡞ΓͮΒ͍

    View Slide

  116. σʔλ
    » Service, Repo, Modelͷࡾ૚
    » Service: Model/RepoΛ·͙ͨॲཧɺτϥϯβΫ
    γϣϯΛఆٛͰ͖Δ
    » Repo: SQLΛॻ͘ʢʂʣɺModelΛฦͨ͠ΓɺӬଓ
    Խ
    » Model: ໨తͱͯ͠͸ߏ଄ମɺ͍ΖΜͳॴͰҾ਺ͷܕ
    ͱͯ͠ࢦఆɻ->isEqual($val)ɺ->toArray()ͱ͔
    ΦϒδΣΫτΒ͍͠؆୯ͳϩδοΫ΋ؚΉ

    View Slide

  117. Service
    !"" lib
    # $"" MyApp
    # !"" Api
    # # !"" Action
    # # !"" Request
    # # $"" Response
    # !"" Model
    # !"" Repo
    # $"" Service
    !"
    $"" tests
    # $"" testTest.php

    View Slide

  118. class UserAccountService {
    public static function getByEmail(string $email, UserAccountRepo $repo=null): ?UserAccount
    {
    $repo = $repo ?? new UserAccountRepo();
    return $repo->getByEmail($email);
    }
    public static function getByEmailAndPassword(string $email, string $password, UserAccountRepo $repo): ?UserAccount
    {
    $ua = static::getByEmail($email, $repo);
    if (is_null($ua)) return null;
    if (!password_verify($password, $ua->hashed_password)) return null;
    return $ua;
    }
    public static function update(UserAccount $ua, UserAccountRepo $repo = null): bool
    {
    $repo = $repo ?? new UserAccountRepo();
    return $repo->update($ua);
    }

    View Slide

  119. » ੩తϝιουͷմ
    » Action͔Β͸repoΛ৮Βͣɺ͜ΕΛ৮Δ
    » ϔϏʔͳ໰͍߹Θ͕ͤൃੜ͢Δ৔߹͸ΩϟογϡΛ͜
    ͜ʹೖΕΔ͜ͱ΋
    » Modelͱ1:1ʹͳΒͳ͍ɺModelʹରͯ͠ෳ਺ͷ
    Service͕͋Δ͜ͱ΋͋Δ͠ɺService͕ෳ਺ͷ
    ModelΛૢ࡞͢Δ͜ͱ΋͋Δɻ
    » Service͔ΒServiceΛ৮Δࣄ΋͋Δ

    View Slide

  120. Repo
    !"" lib
    # $"" MyApp
    # !"" Api
    # # !"" Action
    # # !"" Request
    # # $"" Response
    # !"" Model
    # !"" Repo
    !"
    # $"" Service
    $"" tests
    # $"" testTest.php

    View Slide

  121. class UserAccountRepo extends DB {
    public function getByEmail(string $email): ?UserAccount {
    $pdo = static::getPdo();
    $stmt = $pdo->prepare("SELECT * FROM `user_account` WHERE email = :email");
    $stmt->bindValue('email', $email, \PDO::PARAM_STR);
    $stmt->execute();
    $stmt->setFetchMode(\PDO::FETCH_CLASS, '\MyApp\Model\UserAccount');
    return $stmt->fetch() ?: null;
    }
    public function create(UserAccount $ua): int {
    if(!$ua->isValid()) throw new \InvalidArgumentException("invalid user account model");
    $pdo = static::getPdo();
    $stmt = $pdo->prepare("
    INSERT INTO user_account
    (email, hashed_password, name) VALUES
    (:email, :hashed_password, :name)
    ");
    $stmt->bindValue('hashed_password', $ua->hashed_password, \PDO::PARAM_STR);
    $stmt->bindValue('name', $ua->name, \PDO::PARAM_STR);
    $stmt->bindValue('email', $ua->email, \PDO::PARAM_STR);
    $result = $stmt->execute();
    if (!$result) throw new \RuntimeException("DB query error.");
    return $pdo->lastInsertId('id');
    }

    View Slide

  122. » ӬଓԽ΍σʔλͷϩʔυΛ࢘Δ
    » ModelΛੜ੒ͨ͠ΓɺModelΛอଘͨ͠Γ͢Δ
    » όϦόϦʹSQLΛॻ͍ͯ΋͍͍͠ɺ֎෦APIΛୟ͘ࣄ
    ΋͋Δ
    » ϛεϚονΛٵऩ͢Δ
    » ྫ֎͸جຊ࢖Θͳ͍ɺ0݅औಘͱ͔͸جຊNULLฦ͠
    Ͱ্ҐͰڍಈΛ൑ఆ͢Δ
    » Goͷval, errorΈ͍ͨͳͷ΄͍ͬ͢͠Ͷ… listड
    ͚Ͱ΋͍͍͚Ͳ…ɻ

    View Slide

  123. » setFetchMode(\PDO::FETCH_CLASS,
    UserAccount::class);Λଟ༻
    » SQLΛੜ੒͠ͳ͍Ͱ͢Ή୯ͳΔ̍ߦηϨΫτ͸SQLख
    ॻ͖
    » SQL͸10೥ઓ͑ΔͷͰ
    » ෳࡶͳʢͨͱ͑͹ݕࡧʣΫΤϦ͸ݫ͍͠ͷͰSQLϏϧ
    μ΋࢖͏
    » nilportugues/php-sql-query-builder
    » บ΋ଟগ͋Δ͕ɺਖ਼௚ɺܾఆ൛͕ݟ͔ͭΒͳ͍

    View Slide

  124. Service
    !"" lib
    # $"" MyApp
    # !"" Api
    # # !"" Action
    # # !"" Request
    # # $"" Response
    # !"" Model
    !"
    # !"" Repo
    # $"" Service
    $"" tests
    # $"" testTest.php

    View Slide

  125. Modelྫ
    class UserAccount {
    public $id = 0;
    public $email = "";
    public $hashed_password = "";
    public $name = "";
    public function __construct()
    {
    if ($this->id === 0) return; // PDO fetchͳΒҎ߱΋࣮ߦ͞ΕΔ
    $this->id = (int)$this->id;
    }
    public function getPublicData(): array {
    $list = get_object_vars($this);
    unset($list['id']);
    unset($list['hashed_password']);
    return $list;
    }

    View Slide

  126. » ཉ͍͠σʔλߏ଄͕͋Ε͹ͭ͘ΔɺςʔϒϧͱҰରҰͰ
    ରԠඞਢͰ͸ͳ͍
    » ϓϩύςΟ͸ඞཁͳ෼ͭ͘ΔɺIDEͷิ׬ʹ΋͔ͭ͏
    » ଟ͘ͷέʔεͰ͸ɺίϯετϥΫλ͸FETCH_CLASSܦ༝
    Λ૝ఆɺศརʂ
    » PDO FETCH_CLASS͸શ෦strʹͳΔͷͰɺModelͷίϯ
    ετϥΫλͰม׵ɺ͍ͩ͞
    » Typed Properties͕͖ͨΒઈରʹ͜͜Ͳ͏ʹ͔ͳͬ
    ͯͯ΄͍͠…
    » ͳ͓ɺhydrate΋(΍Ζ͏ͱ͓΋͑͹)͜͜ͰͰ͖Δ

    View Slide

  127. // ଓ͖
    public function setPassword(string $new_plain_password): void {
    $this->hashed_password = password_hash($new_plain_password, PASSWORD_DEFAULT);
    }
    public function passwordVerification(string $plain_pass): bool {
    return password_verify($plain_pass, $this->hashed_password);
    }
    public function isValid(): bool {
    return count($this->validate()) === 0;
    }
    public function validate(): array {
    /* ... লུ ... */
    return []; // is OK
    }

    View Slide

  128. » ͋·Γϝιου͸ੜ΍͞ͳ͍Ͱ͓͘ɺຊ౰ʹ࠷௿ݶ
    ͷΈॻ͘
    » Ϋϥε಺Ͱด͡ΒΕΔΑ͏ͳ؆୯ͳϢʔςΟϦςΟత
    ͳϝιου͸͜͜ʹੜ΍ͯ͠΋ྑ͍
    » generate_uuid,base64url_encode,validate…

    View Slide

  129. σʔλ·ͱΊ
    » ͱʹ͔͘ܕΛ͚ͭΔ
    » ྫ֎͸࠷௿ݶʢओ؍ʣ
    » ฦΓ஋ʹNULLଟ༻͸ɺݹ͍ਓؒͳͷͰؾʹͳΒ
    ͳ͍ ?Type Έ͍ͨʹ͢Ε͹͍͍͠
    » ʢGoΈ͍ͨʹ(v, err)͍ͨ͠…ʣ

    View Slide

  130. ඒ࣮͘͠૷͍ͨ͠Θ͚Ͱ͸ͳ͍
    » ϦϑΝΫλϦϯάͰյΕʹ͍ͨ͘͘͠
    » Ͱ͖Δ͚ͩґଘΛ୯ํ޲ʹʢඞͣɺͰ͸ͳ͍ʣ
    » मਖ਼ͷӨڹ͕޿͘ग़Δ(Ͱͯ͠·͏)ARύλʔϯʹ͸͠ͳ͍
    ʢঢ়ଶ͸Ͱ͖Δ͔͗Γ࣋ͨͤͳ͍ɺ͔͠͠Ϧιʔε͕…ʣ
    » ΄Μ΋ͷͷDataMapper͸ͭΒ͍͆ʢ͋͋ɺΦϨΦϨͩ…
    » ϔϯςίͳHugeͳ࢓༷͕ଞΛߥΒ͞ͳ͍Α͏ʹ͍ͨ͠
    » ҟৗͳཁ͕݅ύϫʔϓϨΠͰ͖ͨΒɺ
    BookInsaneSearchRepoͱ͔ͭͬͯ͘ղܾ͢Δ
    » ਖ਼ؾͳۭؾʹͳͬͨΒɺࣺͯΔʢͯ͢ΒΕΔͷ͔ʁʣ

    View Slide

  131. » ʢҰൠతͳʣFWͰ΍Δͱɺ΍Γํ͕Θ͔Βͳ͔ͬͨ
    Γɺศརػೳ͕͔ͭ͑ͳͯ͘͏Μ͟Γ
    » Θ͔ΒΜʂͱͳͬͯ҆қʹ഑ྻʹม׵ͪ͠Όͬͯ
    ޙͰഁ໓ʢ͜Ε͸ࢲͷษڧෆ଍ͩʣ
    » ԕྀͳ͘ɺςʔϒϧ͸ͦͷ··ͰModelʢͱɺR
    ͱSʣΛ૿΍ͯ͠ରԠ͢ΔɺSQLॻ͘
    » (γϯϓϧͳSQL Builderಉ༷ʹɺγϯϓϧͳ
    Hydrater΄͍͠Ͱ͢Ͷ)
    » Ϟσϧ,DB,(APIͷ)JSONߏ଄Λ߹ΘͤΔن໿ʹҰ୴
    ͞ΑͳΒ

    View Slide

  132. » DB(PDO)ΛૉखͰ͔͍͍ͭͨ࣌ʹORM͸͠ΜͲ͍
    » ී௨ͷORM͸ςʔϒϧͷΧϥϜͷ૿ݮʹ͸ରԠ͠
    ΍͍͕͢ɺӡ༻ϑΣʔζͰ͸ςʔϒϧͷΧϥϜͦ
    Μͳʹ૿ݮ͠ͳ͍ؾ͕͢Δʢओ؍ʣ
    » γϯϓϧͳΫΤϦ͸ΫΤϦϏϧμͷඞཁੑ͕͋Μ
    ·Γͳ͍
    » ΫΤϦϏϧμ͕bindValueͷܕΛͪΌΜͱ͋ͭ
    ͔ͬͯ͘Εͳ͍͜ͱ͕ଟ͍…
    » ʮ͑ͬɺ͜ΕͲ͔͜ΒͲ͜·ͰτϥϯβΫγϣϯͳ
    ͷʁϩʔϧόοΫ͸ʁʯ

    View Slide

  133. » ViewɺController૚͸৐Γ׵͑΍͍͢ɺಉ͡ϨΠϠ
    Ͱͷґଘ͕͘͢ͳ͍
    » ʢ͍ΘΏΔʣModel͸ॎஅɺԣஅతʹґଘ͢Δ͜ͱ
    ʹͳΓ͕ͪɺ͜͜͸ૈ৯ʹͨ͠΄͏͕௕ੜ͖ʹ͖͘
    ͧʢओ؍

    View Slide