在本文中,我們來細化講講函數計算中 php runtime 中的異常處理問題,在官方文檔中 php runtime 錯誤處理 沒有講解函數計算php runtime 環境中對於具體的錯誤類型是怎麼處理的?比如級別很低的notice或者warning, 先來看幾個例子:
example
Warning
<?php
function handler($event, $context) {
$a = 1/0;
return "ok";
}
執行結果:
{
"errorMessage": "Division by zero",
"errorType": "ErrorException",
"stackTrace": {
"file": "/code/index.php",
"line": 3,
"traceString": ""
}
}
NOTICE
<?php
function handler($event, $context) {
$a = ["a" => 1, "b" => 2];
$b = $a["c"];
return "ok";
}
執行結果:
{
"errorMessage": "Undefined index: c",
"errorType": "ErrorException",
"stackTrace": {
"file": "/code/index.php",
"line": 11,
"traceString": ""
}
}
從上面兩個例子我們可以看出,函數計算的 php runtime 對代碼檢查十分嚴格,不管什麼級別的ERROR_TYPE, 都是按照異常來處理,但是有些使用有些php庫的時候,可能會有一些warning或者notice,這個時候會導致在函數計算的環境中不能使用這種php 庫,比如aliyun-openapi-php-sdk
比如下面的代碼:
<?php
require_once __DIR__ . '/aliyun-openapi-php-sdk/aliyun-php-sdk-core/Config.php';
use imm\Request\V20170906 as Imm;
define('PREVIEWURL', 'https://preview.imm.aliyun.com/index.html');
function handler($event, $context) {
$accessKeyId = $context["credentials"]["accessKeyId"];
$accessKeySecret = $context["credentials"]["accessKeySecret"];
$securityToken = $context["credentials"]["securityToken"];
$region = $context['region'];
$iClientProfile = DefaultProfile::getProfile(
$region,
$accessKeyId,
$accessKeySecret,
$securityToken
);
$client = new DefaultAcsClient($iClientProfile);
$PREVIEWTGTPATH = 'fc-demo-preview-output-php';
$immProject = "imm-demo";
$srcUri = "oss://fc-imm-demo/test-data/office/test.pptx";
$bucket = "fc-imm-demo";
$fileName = "test.pptx";
$tgtUri = sprintf("oss://%s/%s/%s", $bucket, $PREVIEWTGTPATH, $fileName);
$request = new Imm\CreateOfficeConversionTaskRequest();
$request->setProject($immProject);
$request->setSrcUri($srcUri);
$request->setTgtType("vector");
$request->setTgtUri($tgtUri);
$response = $client->getAcsResponse($request);
print_r($response);
}
執行就會收到這個錯誤, 上面 example 中的 NOTICE 轉變爲exception:
{
"errorMessage": "Undefined index: cn-hangzhou#imm",
"errorType": "ErrorException",
"stackTrace": {
"file": "/code/aliyun-openapi-php-sdk/aliyun-php-sdk-core/Regions/LocationService.php",
"line": 58,
"traceString": ""
}
}
php runtime 中自定義error_handler
當遇見上面所述對的問題時,我們如何規避這種問題呢?答案是使用set_error_handler
來定義自己的處理方法,從而屏蔽runtime中嚴格處理, 對於 Warning 和 Notice 這種級別等錯誤, 詳情可以參考:http://www.php.net/manual/zh/function.set-error-handler.php
對於上面這種問題,我們修改代碼如下:
<?php
require_once __DIR__ . '/aliyun-openapi-php-sdk/aliyun-php-sdk-core/Config.php';
use imm\Request\V20170906 as Imm;
define('PREVIEWURL', 'https://preview.imm.aliyun.com/index.html');
function myErrorHandler($errno, $errstr, $errfile, $errline) {
if (!(error_reporting() & $errno)) {
return false;
}
switch ($errno) {
case E_USER_ERROR:
$errInfo = array(
"errorMessage" => $errstr,
"errorType" => \ServerlessFC\friendly_error_type($errno),
"stackTrace" => array(
"file" => $errfile,
"line" => $errline,
),
);
throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
break;
default: // E_USER_WARNING | E_USER_NOTICE
break;
}
/* Don't execute PHP internal error handler */
return true;
}
// set to the user defined error handler
set_error_handler("myErrorHandler");
function handler($event, $context) {
$accessKeyId = $context["credentials"]["accessKeyId"];
$accessKeySecret = $context["credentials"]["accessKeySecret"];
$securityToken = $context["credentials"]["securityToken"];
$region = $context['region'];
$iClientProfile = DefaultProfile::getProfile(
$region,
$accessKeyId,
$accessKeySecret,
$securityToken
);
$client = new DefaultAcsClient($iClientProfile);
$PREVIEWTGTPATH = 'fc-demo-preview-output-php';
$immProject = "imm-demo";
$srcUri = "oss://fc-imm-demo/test-data/office/test.pptx";
$bucket = "fc-imm-demo";
$fileName = "test.pptx";
$tgtUri = sprintf("oss://%s/%s/%s", $bucket, $PREVIEWTGTPATH, $fileName);
$request = new Imm\CreateOfficeConversionTaskRequest();
$request->setProject($immProject);
$request->setSrcUri($srcUri);
$request->setTgtType("vector");
$request->setTgtUri($tgtUri);
$response = $client->getAcsResponse($request);
print_r($response);
}
總結
本文中,詳細解析了函數計算 php runtime 中對於異常的處理, 在php runtime 中,嚴格規範代碼,我們期望加強檢查以便減少用戶編寫diamante犯錯的可能,但是針對一些第三方庫的引入使用可能因爲warning或者notice而無法使用時,函數計算允許用戶通過自定義的set_error_handler來覆蓋runtime中默認處理。