소스 수준에서 Composer 패키지 재정의
시나리오
Laravel 프레임워크에서
cleanBindings
클래스( source )의 함수Builder
를 재정의하고 싶다는 글을 썼습니다. 클래스 자체를 확장하는 것은 함수가 공용이고 클래스가 최종으로 표시되지 않기 때문에 문제가 되지 않습니다. 여기서 진짜 문제는 Builder
가 프레임워크 코드의 여러 수준에 있는 하드 코딩된 종속성이라는 것입니다.이제 면책 조항으로 이 작업을 수행할 수 있는 다른 방법이 있습니다. 그리고 일반적으로 프로덕션 코드에 내 솔루션을 사용하는 것은 권장하지 않습니다. 그런 식으로 메커니즘을 살펴 보겠습니다.
재정의 대신 덮어쓰기
PHP는 스크립팅 언어이므로 Composer로 설치하는 종속성은 결국 디스크에 있는 PHP 소스 파일 묶음에 불과합니다. 이론적으로 클래스를 확장하여 라이브러리 함수를 재정의하는 대신 공급업체 디렉토리에서 해당 소스 파일을 열고 코드를 직접 편집할 수 있습니다.
물론 여기에는 많은 문제가 따릅니다. 우선 변경 사항은 패키지를 업데이트하거나 다시 설치할 때까지만 유지됩니다. 둘째, 팀의 다른 누구도 변경 사항을 받지 못합니다. 또한 변경으로 인해 해당 기능에 의존하는 사람이 중단되지 않도록 해야 합니다. 여기에는 설치한 다른 패키지도 포함될 수 있습니다. 그러나 후자를 보장할 수 있다면 소스 코드 변경을 자동화하는 문제일 뿐입니다.
Arralyn에서 Pexels 님의 사진
더러운 짓을 하고
패키지를 설치할 때 소스 코드 변경 사항이 적용되고 업데이트로 덮어쓰지 않도록 해야 합니다. 편리하게도 컴포저가
post-autoload-dump
이벤트 형식으로 고리를 제공합니다. 설명서에는 다음과 같이 명시되어 있습니다.post-autoload-dump: occurs after the autoloader has been dumped, either during
install
/update
, or via thedump-autoload
command.
작성기 스크립트documentation에 따르면 후크 콜백을 자동 로드 가능한 클래스의 정적 함수로 정의할 수 있습니다. 다음과 같은 프로젝트 구조를 사용하여 composer.json 파일에서 후크를 정의할 수 있습니다.
project
|-- scripts
| +-- ComposerScripts.php
|-- src
|-- vendor
|-- composer.json
+-- composer.lock
{
"autoload": {
"psr-4": {
"App\\": "src/",
"Scripts\\": "scripts/"
}
},
"scripts": {
"post-autoload-dump": [
"Scripts\\ComposerScripts::postAutoloadDump"
]
}
}
이
ComposerScripts
클래스와 작동하는지 빠르게 확인합시다.<?php
namespace Scripts;
class ComposerScripts
{
public static function postAutoloadDump($event)
{
echo 'I am gonna use this'.PHP_EOL;
}
}
$ composer dump-autoload
Generating autoload files
Scripts\ComposerScripts::postAutoloadDump
I am gonna use this
Generated autoload files
머리 이식
Shuxuan Cao에서 Pexels 님의 사진
다음으로 소스 파일에 있는
cleanBindings
의 함수 본문을 우리 자신의 것으로 바꾸고 싶습니다. 하지만 다음에 Laravel 개발자가 파일 업스트림을 업데이트할 때 깨지기 쉬운 방식으로 어떻게 해야 할까요?환상적인nikic/PHP-Parser 프로젝트를 사용하여 PHP 코드를 AST로 구문 분석하고 함수 본문을 바꾼 다음 다시 PHP 코드로 변환할 수 있습니다. 많은 작업처럼 들리지만 파서가 우리를 위해 모든 무거운 작업을 수행합니다.
use PhpParser\Node;
use PhpParser\NodeFinder;
use PhpParser\ParserFactory;
function replaceCleanBindingsBody(string $srcPath)
{
$code = file_get_contents($srcPath);
// Parse the source code.
$parser = (new ParserFactory())->create(ParserFactory::PREFER_PHP7);
$stmts = $parser->parse($code);
// Find the node of the cleanBindings function in the AST.
$nodeFinder = new NodeFinder();
$builderClass = $nodeFinder->findFirstInstanceOf($stmts, Node\Stmt\Class_::class);
$cleanBindingsFunction = $nodeFinder->findFirst($builderClass->stmts, function(Node $node) {
return $node instanceof Node\Stmt\ClassMethod
&& $node->name->toString() === 'cleanBindings';
});
$newCleanBindingsCode = <<<'PHP'
<?php
function donor() {
// Up to you
return [];
}
PHP
;
// Transplant the body of the donor to our patient.
$donorFunction = $parser->parse($newCleanBindingsCode)[0];
$cleanBindingsFunction->stmts = $donorFunction->stmts;
// Dump PHP code.
$prettyPrinter = new \PhpParser\PrettyPrinter\Standard();
$newCode = $prettyPrinter->prettyPrintFile($stmts);
file_put_contents($srcPath, $newCode);
}
무엇이 남았나요?
코딩 측면에서 PHP-Parser를 사용하기 위해서는
ComposerScripts
클래스에 컴포저 오토로더 파일이 필요합니다. 이 게시물에서 논의된 내용으로 전체sample project를 업로드했습니다.이 권한을 책임감 있게 사용하십시오.
TO THE MAXIMUM EXTEND PERMITTED BY APPLICABLE LAW, THE AUTHOR OF THIS BLOG POST SHALL NOT BE LIABLE FOR ANY DAMAGE TO CODE BASES, OR PRODUCTION SYSTEMS, OR THE TIME LOST DUE TO HOUR-LONG DEBUGGING SESSIONS RESULTING FROM APPLYING THE TECHNIQUES DESCRIBED IN THIS BLOG POST. THE MATERIALS IN THIS BLOG POST COMPRISE THE AUTHOR'S VIEWS AND DO NOT CONSTITUTE PROFESSIONAL ADVICE, you know.
게시물 Overriding Composer packages at the source level이 hbgl에 처음 나타났습니다.
Reference
이 문제에 관하여(소스 수준에서 Composer 패키지 재정의), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/hbgl/overriding-composer-packages-at-the-source-level-21oc텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)