Page 1
ふつうのpixivのつくりかた
An introduction to building pixiv for ordinary PHPers
pixiv Inc.
USAMI Kenta
2023-07-26 PHP の今を語る!4社合同勉強会
公開日:
by USAMI Kenta@tadsan
にオンラインのZoom会議で開催された『【PHP Tech Talk】PHPの今を語る!4社合同勉強会』で15分枠として発表しました。
2023-07-26 PHP の今を語る!4社合同勉強会
お前誰よ
pixiv.netとは
フレームワークが使われていない
諸説ありますが難しい構造にはなってない
メタプログラミングは基本的にあまりやらない
(こっそり使ってる部分もありますが大筋は追えるはず)
PHP詳しくない人でも雰囲気に従って書けばセキュリティの問題は起こさないように
pixivのPHP
include_onceいっぱい
エラーハンドリング(してないページもあった)
<?php // www.pixiv.net/htdocs/hoge.php require_once __DIR__ . '/../inc/bootstrap.php';include_once INC_PATH . '/Hoge/Fuga.php';include_once INC_PATH . '/Hoge/Piyo.class.php';try {display()} catch (Exception $e) {error::exception_error($e);}
この下にもいっぱい
ファイルローカルな
function display() {// ...
グローバル関数
<?php // www.pixiv.net/htdocs/hoge.php require_once __DIR__ . '/../inc/bootstrap.php';
include_once一個だけ
AppRunner::execute(new Www_HogeController);
このクラスは自動ロードされる
htdocs/hoge.phpは消滅
URLとファイルは切り離され
マップの一要素に
全URLが1ファイルに
final class Controller_WwwRoutes {public static function getRoutes() {$route_map = ['/' => ['action' => function () {Www_IndexController::main();},],'/hoge.php' => ['action' => function () {Www_HogeController::main();},
... ですっきり
<?php // WwwRoutes.php public static function getRoutes() {return ['/' => Www_View_IndexController::main(...),'/hoge' => Www_View_HogeController::main(...),'/.well-known/change-password' => fn() =>Util_Http::redirect_and_exit(ReverseRoute::fullAccountsPasswordChange([])),],
<?php
whoops
final class PCAppRunner {public static function execute(Closure $action) {try {Controller_Util::turnOnWhoops();Controller_Util::redirectToHttps();
パソコン版
$action();} catch (\Throwable $exception) {PCAppRunner::setHttpStatus(500);Controller_Util::displayWhoops($exception);
開発しやすさのための取り組み
CI (Jenkins, GitLab CI)
PHPで開発しにくいところ
$id = $_GET['user_id'];if (is_numeric($id)) User_Common::getById($id);else error("不正な入力です");
ParamHelper
$id = ParamHelper::get('id')->asPositiveInt();$user = User_Common::getById($id);
ParamHelper
$mode = ParamHelper::get('mode')->asStringInArray['hoge', 'fuga']);
<a href="{$smarty.const.SYSTEM_URL_WWW|escape}member_illust.php?id={$user.id|escape}">{$user.name|escape}</a>
<a href="{reverse_route page='fullWwwMemberProfile' id=$user.id}">{$user.name|escape}</a>
/*** @route\example https://www.pixiv.net/member.php?id=12345 {id: 12345}* @route\example https://www.pixiv.net/member.php?id=12345&utm_source=xxxxx{id: 12345, utm_source: "xxxxx"}*/public static function fullWwwMemberProfile(array $params){Util_Assert::num($params['id']);
return ReverseRoute::buildUrl(SYSTEM_URL_WWW, '/member.php', ['id'],$params);}
#[RouteExample('https://www.pixiv.net/member.php?id=12345', ['id'=> 12345])#[RouteExample('https://www.pixiv.net/member.php?id=12345&utm_source=xxxxx,['id' => 12345, 'utm_source' => 'xxxxx'])public static function fullWwwMemberProfile(array $params){Util_Assert::num($params['id']);
return ReverseRoute::buildUrl(SYSTEM_URL_WWW, '/member.php', ['id'],$params);}
でもPDOで複雑なクエリを書こうとすると文字列結合が避けられない…
PxvSql
する %if や %for の記法で条件分岐や複数SETなども可能
PxvSql
TetoSQL
リを一覧できるビューアーもある
予期せぬ問題を引き起こすことがある (コンフリクト解決が大変)
鮮度のよいうちにマージしておきたい (リリース時の変更を最小限に)
if ($_SERVER['REMOTE_ADDR'] === OFFICE_IP) {hogehoge();}
if (ABTest_DevToggle::isEnabledDevToggle('hogeFunc')) {hogehoge();}
pixivが2007年からユーザーに価値を提供してきた結果は変らない
まとめ
いっしょに開発していきましょう!!!!
読めるのでおすすめ
