無法理解 PHP 代碼示例怎麼辦?

php武器庫 發佈 2023-03-06T22:48:01.478327+00:00

PHP的代碼示例也有很多種情況,最簡單的是某個依賴庫中文檔的示例,難一點的是某個業務實現的代碼,再難一點的是設計模式中的一些例子。

一般PHP代碼有哪些難度?應該如何理解PHP的代碼?本文手把手教你如何讀代碼。

PHP的代碼示例也有很多種情況,最簡單的是某個依賴庫中文檔的示例,難一點的是某個業務實現的代碼,再難一點的是設計模式中的一些例子。第一種情況下,不應該出現無法理解的情況,因為這類代碼基本都是最簡單最易讀的寫法了。

最簡單的代碼示例

以阿里雲的OSS上傳為例,一般來講阿里雲的文檔還是很舒服的:

<?php
if (is_File(__DIR__ . '/../autoload.php')) {
    require_once __DIR__ . '/../autoload.php';
}
if (is_file(__DIR__ . '/../vendor/autoload.php')) {
    require_once __DIR__ . '/../vendor/autoload.php';
}

use OSS\OssClient;
use OSS\Core\OssException;

// 阿里雲帳號AccessKey擁有所有API的訪問權限,風險很高。強烈建議您創建並使用RAM用戶進行API訪問或日常運維,請登錄RAM控制台創建RAM用戶。
$accessKeyId = "yourAccessKeyId";
$accessKeySecret = "yourAccessKeySecret";
// yourEndpoint填寫Bucket所在地域對應的Endpoint。以華東1(杭州)為例,Endpoint填寫為https://oss-cn-hangzhou.aliyuncs.com。
$endpoint = "yourEndpoint";
// 填寫Bucket名稱,例如examplebucket。
$bucket= "examplebucket";
// 填寫Object完整路徑,例如exampledir/exampleobject.txt。Object完整路徑中不能包含Bucket名稱。
$object = "exampledir/exampleobject.txt";
// <yourLocalFile>由本地文件路徑加文件名包括後綴組成,例如/users/local/myfile.txt。
// 填寫本地文件的完整路徑,例如D:\\localpath\\examplefile.txt。如果未指定本地路徑,則默認從示例程序所屬項目對應本地路徑中上傳文件。
$filePath = "D:\\localpath\\examplefile.txt";

try{
    $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint);

    $ossClient->uploadFile($bucket, $object, $filePath);
} catch(OssException $e) {
    printf(__FUNCTION__ . ": FAILED\n");
    printf($e->getMessage() . "\n");
    return;
}
print(__FUNCTION__ . "OK" . "\n");

以上是他的一個文檔代碼,它的文檔還有更好的一點,就是幾乎每一行都有注釋,但即便沒有注釋,當你面對這些代碼的時候,你也應該「翻譯」成下面的樣子。

引入文件(require_once)
通過命名空間引入類庫代碼(use xxx)
設置一大堆的帳號參數(聲明各個變量)
實例化客戶端(new )
通過客戶端對象上傳文件,傳入指定參數(調用uploadFile方法)
處理一些錯誤(列印錯誤信息)
處理業務情況(輸出OK)

如果這段代碼你做不到這個水平,看不懂,那可以分成兩個情況,

1:你是真的不懂,可能不適合編程。

2:你被各種英文單詞和符號迷惑了,這說明你的PHP基礎很差勁,連語法都沒適應,要繼續學習基本的知識。

3:你沒有一個明確的編程目的,沒有理解到這段代碼的「功能(需求)」。

上面的代碼,如果你不清楚什麼是require_once use $ ; ( ) new try 這些東西,你可以通過學習語法解決。另外你要有個概念,就是這段代碼是幹什麼的,你要有一個大大的標題在這個代碼的上方,比如「使用阿里的對象存儲客戶端上傳文件」,這也很有助於理解代碼。

難一點的業務代碼

這類代碼你必須要知道編程的目的,必須知道他的功能是什麼,主要是解決什麼問題,才能理解清楚。

比如下面這段代碼:

Route::rule('resizer', function (request $request) {
    $request_src = $request->pathinfo();

    $m = $request->param('m', 1);

    $w = $request->param('w', null);

    $h = $request->param('h', null);

    $src = str_replace('resizer/', '', $request_src);

    $cache_key = "{$src}-{$m}-{$w}-{$h}";

    $content_data = Cache::get($cache_key);

    if (is_null($content_data)) {
        $img_src = App::getRootPath() . 'public/' . $src;

        if (!file_exists($img_src)) {
            return json_message('圖片不存在', 404)->code('404');
        }

        $img = Image::make($img_src);

        if (!is_null($w) || !is_null($h)) {
            $img->resize($w, $h, function ($constraint) use ($m) {
                if ($m == 0) {
                } elseif ($m == 1) {
                    $constraint->aspectRatio();
                } elseif ($m == 2) {
                    $constraint->aspectRatio();
                    $constraint->upsize();
                }
            });
        }


        $img_content = (string)$img->psrResponse()->getBody();


        $img_content_type = $img->mime();

        $content_data = [
            'content' => $img_content,
            'content_type' => $img_content_type
        ];

        Cache::set($cache_key, $content_data);
    }

    $file_name = basename($src);

    return download($content_data['content'])
        ->isContent(true)
        ->name($file_name)
        ->contentType($content_data['content_type'])
        ->mimeType($content_data['content_type'])
        ->expire(25920000)
        ->force(false);
});

這段代碼其實並不是很複雜,通讀下來,你基本可以得到下面的信息:

它接收許多GET參數
這些參數會做一個緩存
在沒有緩存的時候,通過這些參數做一些事
似乎是實現根據參數做圖片的裁剪變形之類的操作
最終以文件的方式響應結果

如果能理解以上的信息,說明你已經讀懂了,但如果要修改他的功能,卻要再做更多理解,比如:

  • 圖片文件的路徑是什麼?
  • 支持什麼樣的圖片操作?

第一個小問題其實很好理解,通過`request_src`變量就可以知道,真實的路徑文件是將這個字符串去掉`resizer/`得來的,然後再拼接系統中的前綴,得到真實的路徑。

至於這個變量是怎麼樣通過GET參數傳過來的,如果用過ThinkPHP,那麼就知道這是框架提供的一個方法,但即便不知道,也不用擔心,這是其他的問題,目前我們已經知道真實的文件路徑是怎麼來的了。

同理,他拼接的前綴具體是多少,是怎麼實現的,如果用過ThinkPHP,那麼很清楚這是什麼,但即便不知道,也不用擔心,目前已經知道「要拼接一個路徑前綴」,就夠了。

如果想知道這些「參數是怎麼傳過來的?」,「拼接的前綴是什麼?」,這些問題,其實最好的答案或許不是閱讀源碼,而是找找框架的文檔,但如果不知道這是什麼框架的話怎麼辦呢?可以定位到這些方法的源碼,或許他是一個依賴庫,這意味著他有composer.json,就意味著知道他的名字和文檔地址了。

其實閱讀源碼是不得已最後的手段,也需要更高的編程經驗和知識。

第二個小問題似乎很複雜,但他跟m、w、h這幾個變量有關係,順著這幾個變量找找,能找到一個if語句判斷,顯然m決定了執行什麼樣的方法,或許意思是「模式」,而w和h應該是圖片的新的寬度和高度,如果找到`$img->resize`的文檔或者閱讀源碼,就能做實這一點。

設計模式的代碼示例

這個很難舉例了,但是這些代碼基本都能看到這個東西:

/**
 * Plugins pass-through.
 *
 * @param string $method
 * @param array  $arguments
 *
 * @return mixed
 */
public function __call($method, array $arguments)
{
    array_unshift($arguments, $this->path);
    $callback = [$this->filesystem, $method];

    try {
        return call_user_func_array($callback, $arguments);
    } catch (BadMethodCallException $e) {
        throw new BadMethodCallException(
            'Call to undefined method '
            . get_called_class()
            . '::' . $method
        );
    }
}

這是一個魔術方法,當調用一個「不可調用」的方法的時候,調用的方法名和參數就會進入這裡。

這個東西是真好用,但是這真不好理解。這個代碼還是很簡單的,當調用這個類的方法不存在的時候,就試圖去調用filesystem屬性的方法,那麼說,這個filesystem屬性應該是一個對象。

這段代碼其實就是league/flysystem的代碼,大家可以去看看。

如果跟蹤filesystem屬性,就會發現,他不是一個具體的類,他聲明的是一個抽象類,這意味著:有可能有多種類型的filesystem。

這就麻煩了,得找到具體是「哪行代碼」實例化了對象並賦給這個屬性。找到這行代碼,估計還會發現,他是通過不同的配置參數來實例化不同的類,就好像「驅動」一樣,不同的驅動是不同的代碼,出現的問題也不一樣。如果是本地存儲,那麼錯誤可能就是沒有權限之類的,而如果是ftp,則網絡出現問題,他也會報錯。

這其實是很簡單的代碼了,只是利用了抽象類而已。

總結

本文希望能展示出開發者是如何理解代碼的。總的來說,必須要打好基礎,否則代碼看著不順眼,很影響閱讀代碼。其次是多了解流行的框架和庫,不求能夠一眼看出代碼,但要一些非常熱門的框架要用過,知道怎麼著文檔。另外,理解代碼是一層一層遞進的,而不是一眼試圖把所有的參數方法搞清楚。

  • 要先清楚功能是幹什麼的
    • 目的是什麼
    • 解決什麼問題
    • 想要什麼結果
    • 比如:把表單提交存起來,並更新帳號,再做個敏感日期
  • 要十分熟悉代碼
    • 看代碼要像看書一樣,不能費勁巴拉
    • 不能看到代碼引起不適
  • 要搞清楚輸入和輸出是什麼
    • 代碼是怎麼開始的
    • 代碼結束的時候做了那些事
  • 可以試圖搞清楚每個參數、每個方法、每行代碼是什麼了
    • 但其實大多數情況下,不需要每個參數和代碼都要搞清楚,大體上知道某個位置在幹什麼就行

原文標題:無法理解 PHP 代碼示例怎麼辦?

原文地址:https://phpreturn.com/index/a64059d62aaf8f.html

原文平台:PHP武器庫

版權聲明:本文由phpreturn.com(PHP武器庫官網)原創和首發,所有權利歸phpreturn(PHP武器庫)所有,本站允許任何形式的轉載/引用文章,但必須同時註明出處。

關鍵字: