首頁 >php框架 >Laravel >總結Laravel中常用的PHP語法有哪些

總結Laravel中常用的PHP語法有哪些

藏色散人
藏色散人轉載
2021-09-09 11:28:262185瀏覽

前言

Laravel框架因為其元件化的設計並適當地使用設計模式,使得框架本身簡潔易擴展。區別於 ThinkPHP 那種整合式功能的框架(功能要么全用要么全不用),Laravel 使用 composer 工具進行 package 的管理,想加功能直接添加組件即可。例如你寫爬蟲使用頁面採集元件: composer require jaeger/querylist

#本文簡單介紹 Laravel 中頻繁用到的 PHP 特性與新語法,具體可參考。

元件化開發

Laravel 進行元件化開發,得益於遵循 PSR-4 規範的 composer 工具,其利用命名空間和自動載入來組織專案文件。更多參考:composer 自動載入機制

命名空間

命名衝突

#在團隊協作、引入第三方依賴程式碼時,往往可能會出現類別、函數和接口重名的情況。例如:

<?php     
# google.php
class User 
{
    private $name;
}
<?php     
# mine.php
// 引入第三方依赖
include &#39;google.php&#39;;

class User
{
    private $name;
}

$user = new User();    // 命名冲突

因為同時定義了類別User 導致命名衝突:

總結Laravel中常用的PHP語法有哪些

##解決方案

從PHP 5.3 開始引入,參考PHP 手冊能知道命名空間有2 個作用:避免

命名衝突、保持命名簡短。例如使用命名空間後:

<?php # google.php
namespace Google;

// 模拟第三方依赖
class User {
    private $name = &#39;google&#39;;

    public function getName() {
        echo $this->name . PHP_EOL;
    }
}
<?php # mine.php
namespace Mine;

// 导入并命名别名
use Google as G;

// 导入文件使得 google.php 命名空间变为 mine.php 的子命名空间
include &#39;google.php&#39;;

/* 避免了命名冲突 */
class User
{
    private $name = &#39;mine&#39;;

    public function getName() {
        echo $this->name . PHP_EOL;
    }
}

/* 保持了命名简短 */
// 如果没有命名空间,为了类名也不冲突,可能会出现这种函数名
// $user = new Google_User();
// Zend 风格并不提倡
$user = new G\User();

// 为了函数名也不冲突,可能会出现这种函数名
// $user->google_get_name()
$user->getName();

$user = new User();
$user->getName();
運行:

$ php demo.php
google
mine
PSR 規格

其實namespace 與檔案名稱無關,但按PSR 標準需求:命名空間與檔案路徑一致&檔案名稱與類別名稱一致。例如Laravel 預設產生的

laravel-demo/app/Http/Controllers/Auth/LoginController.php,其命名空間為App\Http\Controllers\Auth & 類別名為LoginController

遵循規範,上邊的

mine.phpgoogle.php 都應叫User.php

namespace 運算子與

__NAMESPACE__ 魔術常數
...
// $user = new User();
$user = new namespace\User();    // 值为当前命名空间
$user->getName();

echo __NAMESPACE__ . PHP_EOL;    // 直接获取当前命名空间字符串    // 输出 Mine

三種命名空間的導入

<?php namespace CurrentNameSpace;

// 不包含前缀
$user = new User();        # CurrentNameSpace\User();

// 指定前缀
$user = new Google\User();    # CurrentNameSpace\Google\User();

// 根前缀
$user = new \Google\User();    # \Google\User();

全域命名空間

#如果引用的類別、函數沒有指定命名空間,則會預設在當在

__NAMESPACE__下尋找。若要引用全域類別:

<?php namespace Demo;

// 均不会被使用到
function strlen() {}
const INI_ALL = 3;
class Exception {}

$a = \strlen(&#39;hi&#39;);         // 调用全局函数 strlen
$b = \CREDITS_GROUP;          // 访问全局常量 CREDITS_GROUP
$c = new \Exception(&#39;error&#39;);   // 实例化全局类 Exception
多重導入與多個命名空間

// use 可一次导入多个命名空间
use Google,
    Microsoft;

// 良好实践:每行一个 use
use Google;
use Microsoft;
<?php // 一个文件可定义多个命名空间
namespace Google {
    class User {}
}    
    
namespace Microsoft {
    class User {}
}   

// 良好实践:“一个文件一个类”

#匯入常數、函數

從PHP 5.6 開始,可使用

use functionuse const 分別導入函數和常數使用:

# google.php
const CEO = 'Sundar Pichai';
function getMarketValue() {
    echo '770 billion dollars' . PHP_EOL;
}
# mine.php
use function Google\getMarketValue as thirdMarketValue;
use const Google\CEO as third_CEO;

thirdMarketValue();
echo third_CEO;
#運行:

$ php mine.php
google
770 billion dollars
Sundar Pichaimine
Mine
檔案包含

手動載入

總結Laravel中常用的PHP語法有哪些##使用

include

require

引入指定的文件,(字面理解)需注意require 出錯會報編譯錯誤中斷腳本運行,而include 出錯只會報warning 腳本繼續運行。 include 檔案時,會先去php.ini 中設定項目

include_path

指定的目錄找,找不到才在目前目錄下找:

<?php     
// 引入的是 /usr/share/php/System.php
include &#39;System.php&#39;;
自動載入

void __autoload(string $class )

 能進行類別的自動加載,但一般都使用spl_autoload_register 手動進行註冊:

<?php // 自动加载子目录 classes 下 *.class.php 的类定义
function __autoload($class) {
    include &#39;classes/&#39; . $class . &#39;.class.php&#39;;
}

// PHP 5.3 后直接使用匿名函数注册
$throw = true;        // 注册出错时是否抛出异常
$prepend = false;    // 是否将当前注册函数添加到队列头

spl_autoload_register(function ($class) {
    include &#39;classes/&#39; . $class . &#39;.class.php&#39;;
}, $throw, $prepend);
在composer 產生的自動載入檔案laravel-demo/vendor/composer/autoload_real.php  中可看到:

class ComposerAutoloaderInit8b41a
{
    private static $loader;

    public static function loadClassLoader($class)
    {
        if ('Composer\Autoload\ClassLoader' === $class) {
            // 加载当前目录下文件
            require __DIR__ . '/ClassLoader.php';
        }
    }
    
     public static function getLoader()
    {
        if (null !== self::$loader) {
            return self::$loader;
        }
    
        // 注册自己的加载器
        spl_autoload_register(array('ComposerAutoloaderInit8b41a6', 'loadClassLoader'), true, true);
        self::$loader = $loader = new \Composer\Autoload\ClassLoader();
        spl_autoload_unregister(array('ComposerAutoloaderInit8b41a6a', 'loadClassLoader'));

        ...
     }
 
    ...
}
這裡只提一下,具體Laravel 整體是怎麼做自動載入的,後邊的文章會細說。

反射

參考 PHP 手冊,可簡單的理解為在執行時取得物件的完整資訊。反射有5 個類別:

ReflectionClass     // 解析类名
ReflectionProperty     // 获取和设置类属性的信息(属性名和值、注释、访问权限)
ReflectionMethod     // 获取和设置类函数的信息(函数名、注释、访问权限)、执行函数等
ReflectionParameter    // 获取函数的参数信息
ReflectionFunction    // 获取函数信息
例如

ReflectionClass

的使用:

<?php class User
{
    public $name;
    public $age;

    public function __construct($name = &#39;Laruence&#39;, $age = 35) {
        $this->name = $name;
        $this->age  = $age;
    }

    public function intro() {
        echo '[name]: ' . $this->name . PHP_EOL;
        echo '[age]: '  . $this->age  . PHP_EOL;
    }
}

reflect('User');

// ReflectionClass 反射类使用示例
function reflect($class) {
    try {
        $ref = new ReflectionClass($class);
        // 检查是否可实例化
        // interface、abstract class、 __construct() 为 private 的类均不可实例化
        if (!$ref->isInstantiable()) {
            echo "[can't instantiable]: ${class}\n";
        }

        // 输出属性列表
        // 还能获取方法列表、静态常量等信息,具体参考手册
        foreach ($ref->getProperties() as $attr) {
            echo $attr->getName() . PHP_EOL;
        }

        // 直接调用类中的方法,个人认为这是反射最好用的地方
        $obj = $ref->newInstanceArgs();
        $obj->intro();
    } catch (ReflectionException $e) {
            // try catch 机制真的不优雅
            // 相比之下 Golang 的错误处理虽然繁琐,但很简洁
        echo '[reflection exception: ]' . $e->getMessage();
    }
}
運行:
$ php reflect.php
name
age
[name]: Laruence
[age]: 35
其餘4 個反射類別參考手冊demo 即可。 後期靜態綁定

參考PHP 手冊,先看一個例子:

<?php class Base
{
        // 后期绑定不局限于 static 方法
    public static function call() {
        echo &#39;[called]: &#39; . __CLASS__ . PHP_EOL;
    }

    public static function test() {
        self::call();        // self   取值为 Base  直接调用本类中的函数
        static::call();        // static 取值为 Child 调用者
    }
}

class Child extends Base
{
    public static function call() {
        echo &#39;[called]: &#39; . __CLASS__ . PHP_EOL;
    }
}


Child::test();

輸出:

$ php late_static_bind.php
[called]: Base
[called]: Child
在物件實例化時,

self::

會實例化根據定義所在的類,

static::

會實例化呼叫它的類別。

trait

基本上使用

參考PHP 手冊,PHP 雖然是單繼承的,但從5.4 後可透過trait 水平組合“類別”,來實現“類別”的多重繼承,其實就是把重複的函數拆分成triat 放到不同的檔案中,透過use 關鍵字按需引入、組合。可類比 Golang 的 struct 填鴨式組合來實現繼承。例如:

<?php class DemoLogger
{
    public function log($message, $level) {
        echo "[message]: $message", PHP_EOL;
        echo "[level]: $level", PHP_EOL;
    }
}

trait Loggable
{
    protected $logger;

    public function setLogger($logger) {
        $this->logger = $logger;
    }

    public function log($message, $level) {
        $this->logger->log($message, $level);
    }
}

class Foo
{
        // 直接引入 Loggable 的代码片段
    use Loggable;
}

$foo = new Foo;
$foo->setLogger(new DemoLogger);
$foo->log('trait works', 1);
運行:

$ php trait.php
[message]: trait works
[level]: 1

更多參考:我所理解的PHP Trait

重要性質##優先順序

###目前類別的函數會覆寫trait 的同名函數,trait 會覆寫父類別的同名函數( ###use trait### 相當於目前類別直接覆寫了父類別的同名函數)######trait 函數衝突######同時引入多個trait 可用###,### 隔開,即多重繼承。 ###

多个 trait 有同名函数时,引入将发生命名冲突,使用 insteadof 来指明使用哪个 trait 的函数。

重命名与访问控制

使用 as 关键字可以重命名的 trait 中引入的函数,还可以修改其访问权限。

其他

trait 类似于类,可以定义属性、方法、抽象方法、静态方法和静态属性。

下边的苹果、微软和 Linux 的小栗子来说明:

<?php trait Apple
{
    public function getCEO() {
        echo &#39;[Apple CEO]: Tim Cook&#39;, PHP_EOL;
    }

    public function getMarketValue() {
        echo &#39;[Apple Market Value]: 953 billion&#39;, PHP_EOL;
    }
}


trait MicroSoft
{
    public function getCEO() {
        echo &#39;[MicroSoft CEO]: Satya Nadella&#39;, PHP_EOL;
    }

    public function getMarketValue() {
        echo &#39;[MicroSoft Market Value]: 780 billion&#39;, PHP_EOL;
    }

    abstract public function MadeGreatOS();

    static public function staticFunc() {
        echo &#39;[MicroSoft Static Function]&#39;, PHP_EOL;
    }

    public function staticValue() {
        static $v;
        $v++;
        echo &#39;[MicroSoft Static Value]: &#39; . $v, PHP_EOL;
    }
}


// Apple 最终登顶,成为第一家市值超万亿美元的企业
trait Top
{
    // 处理引入的 trait 之间的冲突
    use Apple, MicroSoft {
        Apple::getCEO insteadof MicroSoft;
        Apple::getMarketValue insteadof MicroSoft;
    }
}


class Linux
{
    use Top {
            // as 关键字可以重命名函数、修改权限控制
        getCEO as private noCEO;
    }

    // 引入后必须实现抽象方法
    public function MadeGreatOS() {
        echo &#39;[Linux Already Made]&#39;, PHP_EOL;
    }

    public function getMarketValue() {
        echo &#39;[Linux Market Value]: Infinity&#39;, PHP_EOL;
    }
}

$linux = new Linux();
// 和 extends 继承一样
// 当前类中的同名函数也会覆盖 trait 中的函数
$linux->getMarketValue();

// trait 中可以定义静态方法
$linux::staticFunc();

// 在 trait Top 中已解决过冲突,输出库克
$linux->getCEO();
// $linux->noCEO();        // Uncaught Error: Call to private method Linux::noCEO() 

// trait 中可以定义静态变量
$linux->staticValue();
$linux->staticValue();

运行:

$ php trait.php
[Linux Market Value]: Infinity
[MicroSoft Static Function]
[Apple CEO]: Tim Cook
[MicroSoft Static Value]: 1
[MicroSoft Static Value]: 2

总结

本节简要提及了命名空间、文件自动加载、反射机制与 trait 等,Laravel 正是恰如其分的利用了这些新特性,才实现了组件化开发、服务加载等优雅的特性。

以上是總結Laravel中常用的PHP語法有哪些的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:wuYin/blog。如有侵權,請聯絡admin@php.cn刪除