경로 패턴의 정규식 개선(Teeny PHP 경로 시스템)
그러나 여기 사이트의 동료는 주로 그 작업을 줄이기 위해 정규식 그룹화를 사용하여 시스템을 개선할 것을 제안했습니다.
그렇게 간단하지 않았습니다. 이 경우 인덱스 작업이 더 쉬울 것 같았기 때문에 콜백 패턴으로 경로를 격리하여 접근 방식을 변경해야 했습니다.
또 다른 상황은 그룹 이름이 경로 시스템의 사용자에 의해 지정되고 자동이 아니기 때문에 중복 이름을 가진 그룹이 충돌하지 않도록 주의해야 했기 때문에 정규식에서
(?J)
를 사용했습니다. 사용 예:^((?J)(/foo/(?P<user>.*?)/(?P<test>\d+))|(/bar/(?P<user>.*?)/(?P<test>\d+))|(/baz/(?P<name>.*?)/(?P<id>\d+)))$
이 예에서 정규식은 다음과 일치할 수 있습니다.
/foo/username/10
/bar/username/10
/baz/username/10
이 테스트를 위해 세 개의 매우 간단한 스크립트를 만들었습니다. 이 경우에 대한 모든 개체 지향 및 고급 방법론이 과장된 것처럼 보였으므로 스크립트는 매우 간단합니다.
경로 생성.php
<?php
$patterns = array(
'alnum' => '[\da-zA-Z]+',
'alpha' => '[a-zA-Z]+',
'decimal' => '\d+\.\d+',
'num' => '\d+',
'noslash' => '[^\/]+',
'nospace' => '\S+',
'uuid' => '[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}',
'version' => '\d+\.\d+(\.\d+(-[\da-zA-Z]+(\.[\da-zA-Z]+)*(\+[\da-zA-Z]+(\.[\da-zA-Z]+)*)?)?)?'
);
$paramRoutes = array();
$paramCallbacks = array();
for ($i = 0; $i < 300; ++$i) {
$paramRoutes[] = "/{$i}/<user>/<test:num>";
$paramCallbacks[] = "callback_{$i}";
}
$paramRoutes[] = '/foo/<name>/<id:num>';
$paramCallbacks[] = 'callback_success1';
$paramRoutes[] = '/aaa/bbb/ccc';
$paramCallbacks[] = 'callback_success2';
// To simulate $_SERVER['PATH_INFO']
$pathinfo = '/foo/bar/1234';
위의 스크립트와 같이 원하는 경로는 끝에서 두 번째, 즉 첫 번째 경로와 비교하여 획득해야 하는 루프에서 테스트를 위한 300개의 스크립트 경로도 생성됩니다.
ungroup-routes.php
이 스크립트는 오늘날 Teeny가 이미 하고 있는 것과 유사하게 작동합니다.
<?php
require 'generate-routes.php';
$start = microtime(true);
foreach ($paramRoutes as $index => $value) {
$pRegex = preg_replace($getParams, '(?P<$1><$3>)', $value);
$pRegex = str_replace('<>)', '.*?)', $pRegex);
foreach ($patterns as $pattern => $regex) {
$pRegex = str_replace('<' . $pattern . '>)', $regex . ')', $pRegex);
}
if (preg_match('#^(' . $pRegex . ')$#', $pathinfo, $matches)) {
foreach ($matches as $key => $value) {
if ($value === '' || is_int($key)) {
unset($matches[$key]);
}
}
var_dump($matches);
break;
}
}
echo round(microtime(true) - $start, 6), "s\n";
그룹 경로.php
이 스크립트는 최적화 제안입니다.
<?php
require 'generate-routes.php';
$start = microtime(true);
// Max regex test
$limit = 15;
for ($i = 0, $j = count($paramRoutes); $i < $j; $i += $limit) {
$slice = array_slice($paramRoutes, $i, $limit);
$pRegex = implode(')|(', $slice);
$pRegex = preg_replace($getParams, '(?P<$1><$3>)', $pRegex);
$pRegex = str_replace('<>)', '.*?)', $pRegex);
foreach ($patterns as $pattern => $regex) {
$pRegex = str_replace('<' . $pattern . '>)', $regex . ')', $pRegex);
}
if (preg_match('#^((?J)(' . $pRegex . '))$#', $pathinfo, $matches)) {
foreach ($matches as $key => $value) {
if ($value === '' || is_int($key)) {
unset($matches[$key]);
}
}
var_dump($matches);
break;
}
}
echo round(microtime(true) - $start, 6), "ms\n";
테스트 수행
많은 테스트가 환경에서 직접 수행되지만 거의 동시에 발생하는 여러 HTTP 요청에 대한 영향을 확인해야 했기 때문에 ApacheBench를 사용하기로 결정했습니다.
첫 번째 테스트는 그룹 해제를 실행하는 것이었습니다.
ab -n 1000 -c 10 http://localhost/benchmark-routes/ungroup-routes.php
다음과 같은 결과가 얻어졌습니다.
Requests per second: 1566.68 [#/sec] (mean)
Time per request: 6.383 [ms] (mean)
Time per request: 0.638 [ms] (mean, across all concurrent requests)
Transfer rate: 472.54 [Kbytes/sec] received
첫 번째 테스트는 그룹 해제를 실행하는 것이었습니다.
ab -n 1000 -c 10 http://localhost/benchmark-routes/group-routes.php
다음과 같은 결과가 얻어졌습니다.
Requests per second: 3995.64 [#/sec] (mean)
Time per request: 2.503 [ms] (mean)
Time per request: 0.250 [ms] (mean, across all concurrent requests)
Transfer rate: 1209.19 [Kbytes/sec] received
이와 같은 테스트에서는 초당 평균적으로 얼마나 많은 작업을 수행할 수 있는지 평가됩니다. 즉, 초당 HTTP 요청이 많을수록 좋습니다. 두 번째 다른 테스트와 비교하여 차이가 최소이면 정말 과잉일 수 있습니다.
테스트에 따르면 약 2400(대략 테스트는 항상 다름) 더 많은 HTTP 요청(1초 동안)을 받았습니다.
그러나 이 명백한 개선이 경로가 적은 시스템에 해를 끼치지 않도록 해야 했습니다. 많은 요청에 잘 작동하는 것이 때로는 몇 가지 요청에 해로울 수 있기 때문입니다. 그래서
group-routes.php
의 경로 수를 30으로 줄이고 테스트를 다시 실행했습니다.ungroup-routes.php:
Requests per second: 5361.82 [#/sec] (mean)
Time per request: 1.865 [ms] (mean)
Time per request: 0.187 [ms] (mean, across all concurrent requests)
Transfer rate: 1617.39 [Kbytes/sec] received
그룹 경로.php:
Requests per second: 5361.82 [#/sec] (mean)
Time per request: 1.865 [ms] (mean)
Time per request: 0.187 [ms] (mean, across all concurrent requests)
Transfer rate: 1617.39 [Kbytes/sec] received
그리고 놀랍게도 새로운 구조는 거의 동일한 성능을 가진 경로가 거의 없는 시스템에 영향을 미치지 않았습니다.
새 버전은 이제 https://github.com/inphinit/teeny/releases/tag/0.2.8 또는 작곡가를 사용하여 다운로드할 수 있습니다.
composer create-project inphinit/teeny <project name>
감사
이 개선에 도움이 된 것이 그의 제안이었기 때문에 감사합니다.
Reference
이 문제에 관하여(경로 패턴의 정규식 개선(Teeny PHP 경로 시스템)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/brcontainer/improving-the-regex-in-route-patterns-in-teeny-17fe텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)