Lock in $30 Savings on PRO—Offer Ends Soon! ⏳

現代的 PHP アプリの作り方 / How to build a modern PHP app...

Avatar for kubo-sr kubo-sr
July 05, 2024
40

現代的 PHP アプリの作り方 / How to build a modern PHP application

Avatar for kubo-sr

kubo-sr

July 05, 2024
Tweet

Transcript

  1. #1 Laravel (laravel/laravel) • μ΢ϯϩʔυ਺͕ଟ͍ • ݱ୅త PHP WAF ͱͯ͠͸࠷΋༗໊͔

    • ༗ࢤʹΑͬͯܧଓతʹυΩϡϝϯτ͕຋༁͞Ε͍ͯΔ • ͓ੈ࿩ʹͳ͍ͬͯΔํ͸ͥͻد෇͠·͠ΐ͏ • ΤίγεςϜ΍ؔ࿈ϓϩμΫτ͕๛෋Ͱ͙͢ʹ࢖͑Δ • Laravel Octane ͳͲ 5
  2. #2 Symfony (symfony/symfony-bundle) • ͪ͜Β΋μ΢ϯϩʔυ਺͕ଟ͍ • LTS (௕ظαϙʔτ) ͕͋Δ •

    ػೳ͝ͱʹίϯϙʔωϯτͱͯ͠෼ׂ͞Ε͍ͯΔ • WAF ͱͯ͠ͷ Symfony ͸͜ΕΛ૊Έ߹Θͤͨ΋ͷ • Laravel ͳͲ΋࢖͍ͬͯΔ (symfony/http-foundation ͳͲ) ͷͰ࣮͸͍ΖΜͳ৔ॴʹ͍Δ • ڧྗͳެࣜϓϩϑΝΠϥʔ (symfony/pro fi ler-pack) ͕͋Δ • ೔ຊͰ͸࠾༻ྫΛ͋·ΓΈͳ͍ 6
  3. #3 Laminas (laminas/laminas-mvc) • ex. Zend Framework • ΤϯλʔϓϥΠζ (େن໛)

    Ͱͷ࠾༻ྫ͕ଟ͍ (Β͍͠) • ͪ͜Β΋ίϯϙʔωϯτͱͯ͠ϞδϡʔϧԽ͞Ε͍ͯΔ༷ࢠ 7
  4. #4 Slim (slim/slim) • ʮϚΠΫϩ ϑϨʔϜϫʔΫʯ • WAF ͱͯ͠͸࠷খݶͷػೳηοτ •

    ϝϞϦ࢖༻ྔ͕গͳ͍͔΋ • ۙࠒ͸ Laravel ΍ Symfony ΋খ͞ͳηοτ͔Β࢝ΊΒΕΔͷͰ… 8
  5. #5 WordPress • WordPress ࣗମ͸ Packagist ʹͳ͍ • roots/wordpress (ඇެࣜ)

    • ੈքʹ͋Δ΢ΣϒαΠτͷ 43.3% ͸ WordPress ͱ͞Ε͍ͯΔ • ࠓ͸ WordPress ΋όʔδϣϯ؅ཧͰ͖·͢ • ཧ༝͕ͳ͚Ε͹߹Θͤͯ timber/timber ΍ roots/sage Λ࢖͓͏ 9
  6. #6 Guzzle (guzzlehttp/guzzle) • PHP ϓϩηε͔Β֎෦΁ HTTP ௨৴Λߦ͏ϥΠϒϥϦ (ΫϥΠΞϯ τ)

    • ͪ͜ΒΛ࢖͑Ε͹ ext-curl Λ௚઀࢖͏ཧ༝͸ͳ͍ (͸ͣ) 10
  7. ໔੹ • PHP Ͱ͋Ε͹ Web Application Framework ͸ Laravel ·ͨ͸

    Symfony ͷͲͪΒ͔Λ࢖͍ͬͯ·͢ • ଞͷಛ௃͸ᐆດͰ͢ 12
  8. A. Laravel • OSS Ͱ͸ͪ͜Β͔͠ݟͨ͜ͱ͕ͳ͍ (ݸਓͷײ૝Ͱ͢) • ྑ͘΋ѱ͘΋ easy دΓͰ࢝Ί΍͍͢

    (ݸਓͷײ૝Ͱ͢) • ೔ຊޠͰ͋ͬͯ΋ௐ΂Ε͹ͳʹ͔͠ΒΈ͔ͭΔ 14
  9. ͓࢓ࣄͰ࢖͏ • 👉 ؔ܎ऀશһͰܾΊΑ͏ • ϓϩδΣΫτ (ϓϩμΫτ) ͝ͱʹ໨త͸มΘΔ • ҰൠతͳࢦඪΛڍ͛Δͱ…

    • νʔϜʹৄ͍͠ਓ͕͍Δ • νʔϜ಺Ͱ஌͍ͬͯΔਓ͕ଟ͍ • ։ൃ͕ଓ͘ݟࠐΈ͕ߴ͍ (·ͨ͸ࣗ෼Ͱଓ͚Δ֮ޛ͕͋Δ) 19
  10. ͓͢͢Ίͱ͸͍͏͕ • ࠓͲ͖ͷ WAF ͸͍ͣΕ΋ҰൠతʹඞཁͱͳΔػೳΛ͍࣋ͬͯΔ • ໨త͕ҧ͏ • ͓࢓ࣄͰ͸ͦ΋ͦ΋બ΂ͳ͍͜ͱ͕ଟ͍ •

    ݩ੥͚ʹΑΔཁ݅ • Ϧʔμʔ͕͢ͰʹܾΊ͍ͯΔ • ։ൃதʹ్தࢀՃ • ͔ͭͯ࡞ΒΕͨγεςϜ… 20
  11. Ͱ͸ԿΛॏࢹ͢΂͖͔ • αʔόʔ αΠυ ΞϓϦέʔγϣϯ͸։ൃظؒΑΓӡ༻ظؒͷ΄͏͕ ௕͘ͳΓ͕ͪ • ॳظ։ൃ͸௕ͯ͘΋ 2, 3

    ೥ • ػೳ։ൃɾӡ༻͸௕͚Ε͹ 10 ೥Ҏ্… • 👉 ࡞Γ΍͢͞ΑΓอक͠΍͢͞ͷ΄͏͕େࣄͰ͸ʁ 24
  12. PHP: The Right Way ΛಡΉ • ͍͍ͩͨॻ͍ͯ͋Δ • ࢴ໘ ͱ΍Δؾ

    ͷ౎߹͔Βಛʹ͓΅͑ͯ΄͍͜͠ͱΛൈਮ͢Δ 28
  13. PHP Standards Recommendations (PSR) • PHP ༗ࣝऀ͕ू·Γٞ࿦ͯ͠࡞ΒΕͨඪ४קࠂ • ैΘͶ͹ͳΒͳ͍Θ͚Ͱ͸ͳ͍ •

    ϓϩδΣΫτνʔϜ͝ͱʹै͏΂͖ϧʔϧΛٞ࿦͢΂͖ • ͔͠͠ PSR ʹै͑͹֤πʔϧͷඪ४ϧʔϧΛͦͷ··࢖͑Δ • ϑΥʔϚολʔͳͲ 30
  14. PSR-4: Autoloader • ໊લۭؒΛ΋ͱʹ PHP ΫϥεΛಡΈࠐΉͨΊͷϧʔϧ (࢓༷) • جຊ͸ PHP

    ΫϥεΛॻ͘ • DI (ޙड़) ʹ౎߹͕ྑ͍ͷͰεΫϦϓτ΍ؔ਺͸͋·Γ࢖Θͳ͍ • ࡉ͔͘෼͚ͯΑ͍ • ౷߹͸؆୯͕ͩ෼ׂ͸େม 31
  15. ύοέʔδ؅ཧ • PHP ͷ૊ΈࠐΈؔ਺͚ͩ࢖͏ਓ͸΄ͱΜͲ͍ͳ͍ (͸ͣ) • ୭͔͕࡞ͬͨϥΠϒϥϦΛ࢖͏ͱ͖͸ύοέʔδ؅ཧπʔϧΛ࢖͏ • PHP Ͱ͸

    Composer ͕σϑΝΫτ ελϯμʔυ • PHP ֦ுϞδϡʔϧ΁ͷґଘ΋એݴͰ͖Δ • PSR-4 ʹै͓͚ͬͯ͹ϥΠϒϥϦΛউखʹಡΈࠐΜͰ͘ΕΔ (Autoloading) • ৄࡉ͸ࢴ໘ͱͯ͠௕͘ͳΔͷͰׂѪ 33
  16. Dependency Injection (DI) use Psr\Log\LoggerInterface; class ListBlogArticlesService { // ίϯετϥΫλʔͷܕએݴͰ

    LoggerInterface ͕΄͍͠ͱએݴ͢Δ // Laravel ΍ Symfony Λ࢖͍ͬͯΕ͹ Monolog\Logger ͳͲΛউखʹ༻ҙͯ͠౉ͯ͘͠ΕΔ // ࠷ॳ͸೉͍͜͠ͱ͸ߟ͑ͳͯ͘Α͍ function __construct(private readonly LoggerInterface $logger) {} public function listArticles(): array { $this->logger->info("I've loaded the list of articles :)"); } } 35
  17. ܕએݴ • PHP ͸ಈతܕ෇͚Λߦ͏͕Ҿ਺ɾ໭Γ஋ͷσʔλܕΛ໌ࣔͰ͖Δ • ࢦఆ͕ͳ͚Ε͹ mixedɺͳΜͰ΋ड͚ೖΕΔ • TypeScript ͷ

    any ΍ unknown ͱಉ͡ • ຊ౰ʹ͘͝كʹʮͨͩͷද໌ͳͷʹએݴͱݺͿͷ͸͓͔͍͠ʯͱݴΘ ΕΔ͕ެ͕ࣜʮܕએݴʯͱݺΜͰ͍Δ 37
  18. ྫ: ܕએݴ // ม਺ $name ͸จࣈྻΛऔΓɺ஋Λฦ͞ͳ͍͜ͱΛ͍ࣔͯ͠Δ // ͔͠͠ PHP ͸ॲཧத

    (࣮ߦ࣌) ʹจࣈྻ͕౉͞Εͳ͚Ε͹Τϥʔͱ͢Δ͚ͩ // ͕Μ͹Ε͹֎෦πʔϧΛ࢖ͬͯڧ੍Ͱ͖Δ͕… function greetings(string $name): void { echo 'Hello, ' . $name . '.'; } // ͜ͷͨΊʹ΍Ζ͏ͱࢥ͑͹จࣈྻҎ֎Λ౉͢͜ͱ͸Ͱ͖Δ // (Τϥʔ͕ग़ΔͷͰҙຯ͸ͳ͍) // ͜͜Ͱ͸จࣈྻ (string) Ͱ͸ͳ͘੔਺ (int) Λ౉͍ͯ͠Δ greetings(42); 38
  19. Strict Ϟʔυ • PHP ͸طఆͰ͸σʔλͷܕ͕ҧ͑͹߹ΘͤΑ͏ͱ͢Δ • "ͨͱ͑͹ɺؔ਺ʹ int ͕༩͑ΒΕ͕ͨɺ ύϥϝʔλͰจࣈྻ͕ظ଴

    ͞Ε͍ͯͨ৔߹ɺจࣈྻܕͷ஋Λऔಘ͠·͢ɻ" • Strict ϞʔυͰ͸͜ͷڍಈΛࢭΊΒΕΔ • σʔλܕΛಛఆ͢Δͱߟ͑Δ͜ͱ͕ݮΔ 40
  20. null ڐ༰ • PHP ͸ܕએݴ಺ʹ Union types Λهड़Ͱ͖Δ • ݴޠϨϕϧͰ

    nullable ͱ non-nullable Λ۠ผͰ͖Δ • PHP 8.4 Ͱ͜ͷنଇ͕ڧ͘ͳΔ 42
  21. Nullable type // ԾҾ਺͸ string ͔ int ͔ null ͔…

    function greetings($name): void { // ஋Λݕࠪͯ͠ྫ֎Λ throw ͢Δ͔Ωϟετ͠ͳ͚Ε͹ } // จࣈྻҎ֎౉͞ΕΔ͜ͱ͸ͳ͍ɺnull ݕࠪ͸ෆཁ function typedGreetings(string $name): void { // whatever } // จࣈྻ·ͨ͸ null Λ౉͞ΕΔɺॻ͖ํ͸ 2 ௨Γ͋Δ (ޙऀͷ΄͏͕༏੎͔) // Α͍͜͸ࠞͥͳ͍Α͏ʹ function typedGreetingsWithNull(string|null $firstName, ?string $lastName): void { // ... } 43
  22. ݫີͳ౳Ձԋࢉࢠ • PHP ͸౳Ձԋࢉࢠ͕ 2 छྨ͋Δ (==, ===) • Ұൠతͳ

    `==` ͸ൺֱલʹܕͷ૬ޓม׵ (ࣗಈม׵) ͕ೖΔ • ஋ʹΑͬͯڍಈ͕มΘΓಘΔͷͰ `===` Λ࢖͓͏ 45
  23. ྫ /** * ੔਺Λ;ͨͭड͚औΓɺͦΕΒΛؚΉ੔਺ྻΛ഑ྻͱͯ͠ฦ͠·͢ɻ * * @param int $min Լݶ஋

    * @param int $max ্ݶ஋ * @return array<int> $min ͔Β $max ·Ͱ࿈ଓ͢Δ੔਺஋ */ function range($left, $right) { $range = []; for ($i = $min; $i < $max;) { $range[] = ++$i; } return $range; } 49
  24. assert() • PHP ͷ૊ΈࠐΈؔ਺ • Ҿ਺ʹࣜΛࢦఆ͠ɺ͜Εِ͕஋ͱͳΔ৔߹ྫ֎Λ throw ͢Δ • ຊ൪؀ڥͰ͸࣮ߦ͠ͳ͍Α͏ઃఆͰ͖Δ

    (σϑΥϧτແޮ) • ͜ΕʹΑΓ Validation ͱ͸ͳΒͳ͍ͷͰ஫ҙ • ݺͼग़͠ݩͷաͪΛ஌ΒͤΔͨΊʹ࢖͏ 51
  25. ॲཧΛ෼͚Δ • PHP ͷ֎ͱ௨৴͢Δͱ͖͸ॲཧΛ෼͚Α͏ • ࣗ෼Ҏ֎͕ग़ͯ͘Δͱෆ۩߹͕૿͕͑ͪ • ͜ͷεςοϓ͕Ͱ͖ͨΒؔ৺ࣄʹΑͬͯॲཧΛ෼͚Α͏ • ؔ਺

    (ϝιου) Λ෼ׂ͢Δ͚ͩͰ΋ޮՌత • ಡΉൣғ (είʔϓ) ͸୹͍΄͏͕Α͍ • ཧ۶ͱͯ͠΋֤ॲཧ͕୹͘ͳΔͱෳࡶ͕͞Լ͕Γ΍͍͢ • Cognitive Complexity, Cyclomatic Complexity... • ஫: ͜ͷͩ͘Γ͸ PHP ͸ؔ܎ͳ͍ 53
  26. ྫ 1 function retrieve_articles(): array { return $this->repository->getArticles(); } function

    readable(Article $article): bool { return $article->getPublishedAt() <= (new \DateTime()); } function to_result(Article $article): array { return [ 'author' => $article->getAuthor(), 'content' => $article->getContent(), 'publishedAt' => $article->getPublishedAt(), ]; } function list_articles(): Response { return new Response(array_map( 'to_result', array_filter(retrieve_articles(), 'readable'), )); } 55
  27. ྫ 2 function show(Article $article): array { // ... if

    ($user->isAdmin()) { return extract_all_properties_from_article($article); } else if ($user === $article->getAuthor()) { return extract_safe_properties_from_article($article); } else { throw new UnauthorizedException(); } } function extract_all_properties_from_article(Article $article): array { return $article->toArray(); } function extract_safe_properties_from_article(Article $article): array { return array_diff_key($article->toArray(), []); } 56
  28. ྫ (Illuminate\Bus\Dispatcher) // େ఍ͷ৔߹ $handler->handle() ͷݺͼग़͠ݩҰཡʹ͜ͷॲཧ͸ग़ͳ͍ ($handler ͸ mixed) //

    ࣮ߦͯ͠ελοΫτϨʔεΛݟΔ͔͕Μ͹ͬͯ୳͔͢͠ͳ͍ $callback = function ($command) use ($handler) { $method = method_exists($handler, 'handle') ? 'handle' : '__invoke'; return $handler->{$method}($command); }; 64
  29. Ҿ਺ͱͯ͠ͷ࿈૝഑ྻ • ରॲ๏ 1: Ҿ਺Λͻͱͭͣͭఆٛ͢Δ • ରॲ๏ 2: Ҿ਺ΦϒδΣΫτΛఆٛ͢Δ •

    ϓϩϞʔγϣϯ (8.0)ɺreadonly (8.1)ɺreadonly class (8.2) ͳͲࢧ ԉ͢Δػೳ͕૿͑ͨ 67
  30. ରॲ๏ 1: Ҿ਺ΛͦΕͧΕఆٛ͢Δ function search(array $params): bool { // ...

    // ഑ྻ͕ظ଴͢ΔཁૉΛ͍࣋ͬͯΔͱ͸ݶΒͳ͍ͷͰஞҰ֬ೝͤͶ͹ͳΒͳ͍ // ['containsNumbersOnly'] ʹԿΛ౉ͤ͹Α͍͔΋Θ͔Βͳ͍ (0|1, true|false, ...) if (array_key_exists('containsNumbersOnly', $params) && $params['containsNumbersOnly']) { $client->query(array_key_exists('needle') && false !== preg_match('\A\d+\z', $params['needle'])); } // ... } function typedSearch(string $needle, bool $containsNumbersOnly): bool { // whatever... } 68
  31. ରॲ๏ 2: Ҿ਺༻ΦϒδΣΫτΛఆٛ͢Δ readonly class SearchCondition(public string $needle, public bool

    $containsNumbersOnly) {} function stronglyTypedSearch(SearchCondition $condition): bool { // whatever... } stronglyTypedSearch(new SearchCondition('Article Title', containsNumbersOnly: true)); 69
  32. Τϥʔ੍ޚԋࢉࢠ • PHP ͸ࣗ਎ʹ໰୊͕ى͖ΔͱΤϥʔΛൃੜͤ͞Δ • `Notice: Undefined offset` ͳͲ… •

    ࣜͷલʹ `@` Λ͚ͭΔͱ PHP ࣗ਎ͷΤϥʔΛҰ෦ແࢹͰ͖Δ • ؔ਺ͷ໭Γ஋ͳͲʹΑΔΤϥʔදݱͱ͸ผʹ PHP Τϥʔ͕ൃੜͬ ͢Δ৔߹ʹ࢖͏ • ࠷ۙ͸࢖͏͜ͱ͸ͳ͍ 73
  33. ·ͱΊ • PSR Λ׆༻͠Α͏ • ܕએݴΛ࢖͓͏ • Strict Ϟʔυʹมߋ͠Α͏ •

    ֎෦ͱ௨৴͢Δ (৴༻Ͱ͖ͳ͍஋Λ࢖͏) ॲཧ͸෼͚Α͏ • ௨৴͠ͳͯ͘΋੹຿͝ͱʹ෼͚Α͏ • ม׵ɾܭࢉɾ௨৴ͳͲ… • ϥΠϒϥϦ࣮૷Λड͚౉͢ॲཧ͸ Web Application Framework ʹ·͔ͤΑ͏ • ࣮ྫ͸ެ։Ͱ͖ͳ͍ͷͰ௚઀ͨͣͶ͍ͯͩ͘͞ 80