php系列二之phpstorm Xdebug和laravel常見問題整理

  • 2019 年 11 月 23 日
  • 筆記

常見問題

1. 執行 php artisan migration:make 報 Command "migrate:make" is not defined?

因為 php artisan migrate:make 是 Laravel 4 的語法,而 Laravel5 已經換成了 php artisan make:migration

執行 php artisan make:migration table_name 會為每個表在工程的 database 目錄下的 migrations 目錄下生成一個 php 文件。

如果要將這些文件添加到庫中生成對應的表則需要執行 php artisan migrate

2. 更新依賴時出問題了如何解決?

先 composer clearcache 清理包、倉庫快取,再用 composer update,如果不起效,就刪掉 vendor 目錄重新安裝。

3. Laravel 源碼的結構

  • app:網站的業務邏輯程式碼,例如:控制器/模型/路由等
  • bootstrap:框架啟動與自動載入設置相關的文件
  • config:網站的各種配置文件
  • database:資料庫操作相關的文件
  • public:網站的對外文件夾,入口文件和靜態資源(CSS,JS,圖片等)
  • resources:前端視圖文件和原始資源(CSS,JS,圖片等)
  • storage:編譯後的視圖、基於會話、文件快取和其它框架生成的文件
  • tests:自動化測試文件
  • vendor:Composer 依賴文件
  • app/Http/Controllers:存放控制器
  • app/Http/Middleware:存放中間件
  • resources/views:視圖路徑 blade 視圖

4. laravel 配置文件

  • .env: 環境配置文件
  • .env.example:.env 文件的一個示例
  • .gitignore: git 的設置文件,制定哪些文件會被 git 忽略,不納入文件管理
  • composer.json: 網站所需的 composer 擴展包
  • composer.lock: 擴展包列表,確保這個網站的副本使用相同版本的擴展包
  • gulpfile.js:GULP 配置文件( GULP 後邊會學到)
  • package.json: 網站所需的 npm 包
  • readme.md: 網站程式碼說明文件
  • app/Http/routes.php:網站的大多數路由都定義在該文件中,該文件將會被 AppProvidersRouteServiceProvider 類載入。

5. phpstorm 中使用 laravel 的方法

  • 安裝 Laravel Plugin 插件
  • 安裝 Laravel IDE Helper 程式碼提示

5.1. 使用 composer 安裝插件

composer require barryvdh/laravel-ide-helper

在 config 目錄里的 app.php 文件中的'providers'添加如下內容

BarryvdhLaravelIdeHelperIdeHelperServiceProvider::class,

5.2. 在 app 目錄里的 Providers 目錄里的 AppServiceProvider.php 文件中的

public function register()里輸入如下內容來註冊          if ($this->app->environment() !== 'production') {            $this->app->register(BarryvdhLaravelIdeHelperIdeHelperServiceProvider::class);        }

5.3. 生成程式碼跟蹤支援

php artisan ide-helper:generate

5.4. php artisan serve 啟動服務

artisan 的 serve 命令還支援兩個參數:

  • host 設置主機地址
  • port 設置 web server 監聽的埠號 例如:php artisan serve –port=8888

5.5. 如果添加了 debugbar 拓展

composer require barryvdh/laravel-debugbar

頁面下方會出現:

如何查看 phpinfo

創建一個簡單的文本文檔並命名為 phpinfo.php

程式碼如下:

<?php  phpinfo();  ?>

放入 nginx 或 apache 中之後,通過瀏覽器訪問這個文件即可顯示 PHP 資訊 如:http://192.168.1.100/phpinfo.php

配置 phpstorm+xdebug+laravel 環境來 debug 源碼

1. 安裝

安裝 phpstorm 和 laravel 的部分這裡不再多說,之前都有提到。

安裝 xdebug:

  1. E:softwarenginx-1.10.3>php -v
PHP 7.1.32 (cli) (built: Aug 28 2019 09:08:22) ( NTS MSVC14 (Visual C++ 2015) x64 )Copyright (c) 1997-2018 The PHP GroupZend Engine v3.1.0, Copyright (c) 1998-2018 Zend Technologies
  1. 下載 Xdebug
  • 地址:https://xdebug.org/download.php 下載對應 php 版本的即可。
  • 將下載下來的 dll 文件放置 php 安裝目錄的 ext 目錄中並重命名為 php_xdebug.dll
  • 配置 php.ini,添加以下配置:
[xdebug]zend_extension="E:softwarephp-7.1.32-nts-Win32-VC14-x64extphp_xdebug.dll"xdebug.remote_enable=1xdebug.remote_port=9000xdebug.remote_host=localhostxdebug.profiler_enable=1xdebug.remote_mode = "req"xdebug.trace_output_dir="./xdebug"xdebug.profiler_output_dir="./xdebug"xdebug.remote_handler="dbgp"xdebug.idekey = "phpstorm"  //必填
  • 掃行php -m查看安裝情況:
C:Usersadmin>php -m[PHP Modules]bcmathbz2calendarCorectypecurldatedomexiffileinfofilterftpgdgettextgmphashiconvimapintljsonldaplibxmlmbstringmcryptmysqlimysqlndodbcopensslpcrePDOpdo_mysqlPDO_ODBCpdo_pgsqlpdo_sqlitepgsqlPharreadlineReflectionsessionshmopSimpleXMLsoapsocketsSPLsqlite3standardtidytokenizerwddxxdebugxmlxmlreaderxmlrpcxmlwriterxslzipzlib  [Zend Modules]Xdebug

可以看到Xdebug已經安裝成功。

  • 配置phpstorm,主要參考下面兩張圖片
  • laravel在phpstorm中的配置主要參考:https://www.jetbrains.com/help/phpstorm/laravel.html,這裡只是列出Debug Artisan commands的phpstorm的配置:

圖中arguments配置的是artisan的命令。

源碼跟蹤

Auth::attempt($username, $request->isRemember))

對於Auth的attempt方法,表面上來看我們無從找起,但是進入Auth類會發現,Auth 是通過 Facade 動態綁定的,綁定到哪裡呢,進一步尋找我們發現 在 vendor/laravel/framework/src/Illuminate/AuthServiceProvider 中:

 class AuthServiceProvider extends ServiceProvider{    /**     * Register the authenticator services.     *     * @return void     */    protected function registerAuthenticator()    {        $this->app->singleton('auth', function ($app) {            $app['auth.loaded'] = true;            return new AuthManager($app);        });          $this->app->singleton('auth.driver', function ($app) {            return $app['auth']->guard();        });    }}

默認Auth是綁定了AuthManager:

 <?phpnamespace IlluminateAuth;  use Closure;use InvalidArgumentException;use IlluminateContractsAuthFactory as FactoryContract;class AuthManager implements FactoryContract{    use CreatesUserProviders;      protected $app;      protected $guards = [];      public function guard($name = null)    {        $name = $name ?: $this->getDefaultDriver();          return isset($this->guards[$name])                    ? $this->guards[$name]                    : $this->guards[$name] = $this->resolve($name);    }      public function getDefaultDriver()    {        return $this->app['config']['auth.defaults.guard'];    }      public function __call($method, $parameters)    {          return $this->guard()->{$method}(...$parameters);    }}

並沒有找到 attempt 方法,不過有一個__call 的魔術方法,那肯定是他裡面沒錯了,為了快速找到他究竟是何方神聖,直接用

dd(get_class($this->guard()));

輸出為:

IlluminateAuthSessionGuard

再往下的方法調用都可以通過debug的方式確定實現類了。這裡就不再贅述,詳情見:https://learnku.com/articles/5963/toggle-laravel-login-default-bcrypt-encryption-validation

初始化laravel程式時通過修改庫的方式添加了一個用戶,校驗不通過的問題

Auth.attempt調用了:

IlluminateAuthSessionGuard::attempt: public function attempt(array $credentials = [], $remember = false)    {        $this->fireAttemptEvent($credentials, $remember);        $this->lastAttempted = $user = $this->provider->retrieveByCredentials($credentials);        // If an implementation of UserInterface was returned, we'll ask the provider        // to validate the user against the given credentials, and if they are in        // fact valid we'll log the users into the application and return true.        if ($this->hasValidCredentials($user, $credentials)) {            $this->login($user, $remember);            return true;        }        // If the authentication attempt fails we will fire an event so that the user        // may be notified of any suspicious attempts to access their account from        // an unrecognized user. A developer may listen to this event as needed.        $this->fireFailedEvent($user, $credentials);        return false;    }        /**     * Determine if the user matches the credentials.     *     * @param  mixed  $user     * @param  array  $credentials     * @return bool     */    protected function hasValidCredentials($user, $credentials)    {        return ! is_null($user) && $this->provider->validateCredentials($user, $credentials);    }

然後$this->provider->validateCredentials調用了:

IlluminateAuthEloquentUserProvider::validateCredentials:   public function validateCredentials(UserContract $user, array $credentials)    {        $plain = $credentials['password'];        return $this->hasher->check($plain, $user->getAuthPassword());    }

這裡會發現是通過hasher去check庫里的密碼和登錄端傳入的密碼的,通過debug查看這個hasher為BcryptHasher的一個實例,於是對往庫中添加的密碼123456做如下處理:

   $hasher = new BcryptHasher();        $hashPass = $hasher ->make("123456");        printf($hashPass);

將列印出來的結果添加到庫中的密碼欄即可用該用戶名與密碼登錄。