Magento CLI 2.4.0-ErrorHandler가 프로덕션 모드에서 PHP 오류를 예외로 전환 함
서문 : 저는 개발자 모드에서 개발하고 Magento가 모든 PHP E_NOTICE|E_WARNING|etc.오류를 포착하고 예외를 발생시키고 코드를 커밋하기 전에 이러한 문제를 정리 하는 것을 선호 합니다. 그러나 문제는 타사 확장 프로그램에 있으며 문제를보고하려고합니다.
문제:
제목에서 알 수 있듯이 Magento는 Magento\Framework\App\ErrorHandler::handler프로덕션 모드 에서 PHP 수준 오류를 예외로 변환하고 있습니다. 현재 개발 노력의 일환으로 타사 확장 프로그램에 의존해야하며 다음 E_NOTICE수준 오류를 일으키는 논리적 버그가 Notice: Trying to access array offset on value of type null in /path/to/project/vendor/magento/module-catalog-import-export/Model/Import/Product.php on line 1281있습니다..
이 특정 코드 영역에 익숙한 사람은 버그를 정리해야한다고 말해야한다고 느낄 수 있습니다. 그렇지 않으면 행 type_id및 .NET에 대한 데이터 부족으로 인해 제품 가져 오기가 작동하지 않습니다 _attribute_set. 제 3 자 확장에서 더 나아가서 제 3 자 모듈은 실제로 db로 가져 오기 전에 이러한 중요한 키를 적절하게 설정합니다.
내 문제로 돌아 가기 : 타사 확장의이 문제로 인해 개발자 모드에서 로컬로 가져 오기 실행을 테스트 할 수 없습니다. 예상대로 Magento가이 PHP E_NOTICE 수준 오류를 예외로 변환하기 때문입니다. 가져 오기가 실패합니다. 따라서 로컬에서 이러한 PHP 오류가 예외로 변환되는 것을 방지하기 위해 Magento를 프로덕션 모드로 전환하기로 결정했습니다. 불행히도 이것은 문제를 해결하지 못한 것 ErrorHandler같으며 Magento가 프로덕션 모드에있는 동안이 문제에 대한 예외를 계속 발생시킵니다.
나는 Magento의 코드를 자세히 살펴보기로 결정했고, 처음에 Magento가 PHP 오류에 대한 예외를 던지는 것을 피해야하는 방법 (프로덕션 모드)을 결정할 수없는 것 같습니다. 코드를 밟으면 다음을 볼 수 있습니다.
bin/magentoCLI에서 가져 오기를 실행하므로 실행의 진입 점이됩니다.bin/magento포함을 수행합니다app/bootstrap.phpbootstrap.php즉시 PHP의 오류보고 수준을E_ALLbin/magentoPHP의 오류 처리기를 설정합니다.\Magento\Framework\App\ErrorHandlerbin/magentoSymfony 콘솔 응용 프로그램을 만들고 실행합니다.
현재보고 수준에 관계없이 app/bootstrap.php오류보고 수준을로 설정 하기 때문에 E_ALLMagento 실행 스택의 어딘가에서 현재 애플리케이션 모드를 참조해야한다고 가정 할 수 있습니다. "프로덕션"으로 실행하는 경우 error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING ...)프로덕션 모드에서 이러한 오류에 대한 예외가 발생하지 않도록하는 작업을 수행합니다. 그러나 나는 어디에서도 그러한 논리를 찾을 수 없었다. 따라서 프로덕션 모드가 일반적으로 ErrorHandler이러한 PHP 오류를 처음에 예외로 변환하는 것을 방지하는 방법에 대해 손실 이 있습니다.
내가 직접 수정 ErrorHandler.php하면 false를 반환하는 조건부 바로 앞에 다음을 추가합니다.
echo "errNo: $errorNo\nerror_reporting: ". error_reporting() . "\nbitwise result: " . ($errorNo & error_reporting()) . "\nE_ALL: " . E_ALL . "\n";
콘솔에 다음 출력이 표시됩니다.
errNo: 8
error_reporting: 32767
bitwise result: 8
E_ALL: 32767
따라서는 return false;충족되지 않으며 코드는 E_NOTICE레벨 오류를 예외로 변환합니다 . 이 줄 바로 앞에 $errorNo = $errorNo & error_reporting();다음을 추가합니다. error_reporting(E_ALL & ~E_NOTICE);오류 처리기가 예상대로 false를 반환합니다. 분명히 이것은 해결책이 아니지만 현재 작업을 계속 진행하기 위해 일시적으로 의지 한 것입니다.
참고할 몇 가지 추가 사항 :
- 나는 PHP 바이너리에 전달하려고 시도했지만
-d display_errors=0아무런 효과가 없습니다 (PHP는 여전히 오류를보고하므로error_log) - PHP 바이너리로 전달하려고했지만
-d log_errors=0효과가 없습니다. - 나는 PHP 바이너리로 전달하려고 시도했는데
-d error_reporting=0, Magentobootstrap.php가E_ALL. - 위의 모든 것을 한 번에 개별적으로 시도했습니다.
- 나는 플러시 캐시뿐만 아니라 장애인 캐시를 가지고뿐만 아니라 날아
var/cache와generated/code - 내 전체 응용 프로그램 (백업 날아왔다
app/etc/env.php, HEAD에서 하드 리셋을 실행하기 위해 진행 첫번째),composer install그래서 닦아로, 신선한 종속성을 가져가 어떤 효과를 얻을 수 없습니다 캐시 내가 놓친를 (복원env.php하고 다시 -컴파일 프로덕션 모드) - 캐시는 현재 Magento의
var/cache디렉토리 아래에 즉시 사용 가능한 파일 시스템 캐시로 구성되어 있습니다.
마지막 몇 가지 참고 :
- 대부분의 경우 이것은 Magento 2.4.0의 거의 즉시 설치되는 것입니다. 커스터마이제이션 측면에서 거의 없었으며, 확실히
error_reporting()혼자서 (또는 다른 개발자가이 시점에서 코드를 만지는 유일한 개발자 이기 때문에) 레벨을 수정하지 않았습니다 . - 타사 확장은
firebear/importexport버전3.4.3입니다. 이 확장을 검토해도error_reporting()레벨 이 변경되고 있음이 표시되지 않습니다 . - PHP 버전 : 7.4.9
요약 : Magento 프로덕션 모드 ErrorHandler에서 사소한 PHP 오류에 대한 예외를 계속 throw 하는 이유를 모르겠습니다 .
2020.10.07 수정
FactoryAidan의 답변에 대한 응답 : (원래 질문은 다루지 않지만 처음에 E_NOTICE 수준 오류가 발생하는 이유를 설명합니다.)
E_NOTICE 레벨 오류의 발생은 주로 핵심 Magento 코드의 논리적 버그가 아닌 Firebear_ImportExport의 로직 버그로 인한 것이라고 제 개인적인 의견입니다. 또한 "Magento 코어 코드 null가에서 반환 되었는지 확인 했으므로 $this->skuProcessor->getNewSku($lastSku)Firebear의 확장을 사용할 때 처음에는 문제가되지 않을 것입니다.
이제 내가 여전히 Firebear를 가리키는 이유에 대해 (마 젠토에 대한 비판도 포함되지만 여기서 주요 문제는 Firebear가 Magento가 한 일을 따르지 않는 것입니다).
Magento 2.4.0에서 \Magento\CatalogImportExport\Model\Import\Product2481-2488 행 을 보면 다음을 찾을 수 있습니다.
if ($this->isSkuExist($sku) && Import::BEHAVIOR_REPLACE !== $this->getBehavior()) { // can we get all necessary data from existent DB product? check for supported type of existing product if (isset($this->_productTypeModels[$this->getExistingSku($sku)['type_id']])) {
$this->skuProcessor->addNewSku( $sku,
$this->prepareNewSkuData($sku)
);
이 논리를 말로 표현하면 코드가 다음을 수행하고 있음을 알 수 있습니다 (중요하지 않은 측면 생략).
- SKU가 이미있는 경우
- 기존 SKU
type_id가 유효한 경우 - 그런 다음이 기존 sku 를 SkuProcessor의 새 skus 배열에 추가 합니다.
-- 무엇을 기다립니다? 새 skus 배열에 기존 을 추가 하시겠습니까? 왜 새롭지 않은지, 우리는 문자 그대로 이미 존재한다는 것을 확인했습니다. (이것은 Magento에 대한 나의 비판이있는 곳입니다.
방법을 따기는 우리가 본질적으로 그 결론에 도달, 여기에 호출 : "마 젠토는 기존의 SKU를 업데이트 할 때, 우리는 수정할 수 없습니다 보장되는 type_id과를 attribute_set_id". Magento는 기존의 값 과 값 \Magento\CatalogImportExport\Model\Import\Product::_prepareNewSkuData()을 가진 배열을 구축하는 데 의지하여이 배열을 실제로 기존 데이터 임에도 불구하고 "새로운 sku"로 SkuProcessor에 전달 함으로써 다소 이상한 방식으로 진행됩니다.type_idattr_set_code
그런 다음 이러한 헛소리를 통해 Magento는 기존 skus를 처리 할 때 항상 메서드 내에서 type_idand를 구체적으로 설정하도록 속임수를 사용했습니다 .attr_set_code\Magento\CatalogImportExport\Model\Import\Product::_prepareRowForDb()
파이어 베어는? 기존 제품에서 \ Magento \ CatalogImportExport \ Model \ Import \ Product , and these lines 2481-2488 of the original model don't ever execute. Firebear (intentionally, per their documentation on their website) allows for changing of both type_id andattr_set_code`를 재정의했습니다. 제 생각에는 괜찮습니다. 그러나 제품이 초기 유효성 검사를 통과 한 후에는 "기존 sku 데이터를 새 skus 배열에 추가"하는 작업을 무시하고 이것이 E_NOTICE 수준 오류가 발생하는 이유입니다.
어쩌면 그들은 의도적으로 그렇게를하는 것이,이 작업을 수행하지 않았다 type_id및 attr_set_code네이티브로 "다시"아니다 _prepareRowForDb()방법. 그러나이 경우에도 부모 _prepareRowForDb메서드 를 호출 하고 나중에 가져 오기에서 제공된 데이터로이 두 배열 키 값을 설정하는 것은 정말 간단합니다 .
궁극적으로 내 해결책은 Model\Import\Product클래스를 다시 한 번 인수하여 Firebear를 확장하여 Magento를 확장하는 것이 었습니다 . 여기서는 parent::_prepareRowForDb()나중에 오류보고 수준을 원래 값으로 다시 설정 하기 전에 오류보고 수준을 수정합니다 .
내 소스 코드 :
/***
* E_NOTICE level error is breaking import on updates of existing products
* because \Magento\Framework\App\ErrorHandler is catching the error
* and converting it into an exception.
*
* This error is occurring due to a logical bug in firebear/importexport
*
* Native magento/module-catalog-import-export will invoke
* \Magento\CatalogImportExport\Model\Import\Product\SkuProcessor::addNewSku()
* for rows that have passed validation, when the import behavior update.
*
* firebear/importexport does not, and so the SkuProcessor returns
* null to \Magento\CatalogImportExport\Model\Import\Product::_prepareRowForDb()
* when updating existing SKUs. Immediately afterwards, this error occurs:
*
* Notice: Trying to access array offset on value of type null in
* vendor/magento/module-catalog-import-export/Model/Import/Product.php on line 1281
*
* Combinations of package versions that first discovered to yield this logic error:
* Magento Open Source 2.4.0
* firebear/importexport: 3.4.3
* magento/module-catalog-import-export: 101.1.0
*
* {@inheritDoc}
* @see \Firebear\ImportExport\Model\Import\Product::_prepareRowForDb()
* phpcs:disable PSR2.Methods.MethodDeclaration.Underscore
*/
protected function _prepareRowForDb(array $rowData): array { $level = error_reporting();
if (E_NOTICE & $level === 0) { return parent::_prepareRowForDb($rowData);
}
error_reporting($level & ~E_NOTICE); $rowData = parent::_prepareRowForDb($rowData); error_reporting($level);
return $rowData;
}
답변
🔥 Magento 2.4.0과 Firebear도 사용하고 있습니다.
⚠️ 이것은 다음과 같은 Magento Core 버그의 결과입니다.
vendor/magento/module-catalog-import-export/Model/Import/Product.php::_prepareRowForDb
어디:
- 라인 1280 :
$this->skuProcessor->getNewSku($lastSku)반환 유형을 가질 수array|null있지만null처리되지 않습니다.
✅ .patch기존 설치에서 버그가 발생한 코어 모듈을 업데이트 할 다음 파일을 사용하세요.
- M2.4.0 패치에서 두 array | null 반환 유형을 처리합니다. getNewSku()
로 패치를 설치하려면 composer.json요점 링크 ☝️의 첫 번째 주석을 참조하십시오.
ℹ️ 이 솔루션은 Magento Enterprise Cloud Edition 환경에서 테스팅 을 성공적으로 통과했습니다.