国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

反射在 PHP 中的應(yīng)用

stormgens / 1984人閱讀

摘要:反射在每個(gè)面向?qū)ο蟮木幊陶Z言中都存在,它的主要目的就是在運(yùn)行時(shí)分析類或者對(duì)象的狀態(tài),導(dǎo)出或提取出關(guān)于類方法屬性參數(shù)等的詳細(xì)信息,包括注釋。反射是操縱面向?qū)ο蠓缎椭性P偷模捎糜跇?gòu)建復(fù)雜,可擴(kuò)展的應(yīng)用。

反射在每個(gè)面向?qū)ο蟮木幊陶Z言中都存在,它的主要目的就是在運(yùn)行時(shí)分析類或者對(duì)象的狀態(tài),導(dǎo)出或提取出關(guān)于類、方法、屬性、參數(shù)等的詳細(xì)信息,包括注釋。 反射是操縱面向?qū)ο蠓缎椭性P偷?API,可用于構(gòu)建復(fù)雜,可擴(kuò)展的應(yīng)用。反射在日常的 Web 開發(fā)中其實(shí)用的不多,更多的是在偏向底層一些的代碼中,比如說框架的底層中依賴注入、對(duì)象池、動(dòng)態(tài)代理、自動(dòng)獲取插件列表、自動(dòng)生成文檔以及一些設(shè)計(jì)模式等等,都會(huì)大量運(yùn)用到反射技術(shù)。
PHP 的反射 API 很多,但是常用的一般都是 ReflectionClassReflectionMethod:
1.ReflectionClass
這個(gè)是用來獲取類的信息,可以簡單測(cè)試一下:

class Student {
    private    $name;

    public function setName($name)
    {
         $this->name = $name;
    }
 
    protected function getName()
    {
        return $this->name;
    }
 }

獲取類的方法列表:

$ref = new ReflectionClass(Student::class);
var_dump($ref->getMethods());

返回的是一個(gè) ReflectionMethod 的數(shù)組:

array(1) {
  [0]=>
  object(ReflectionMethod)#2 (2) {
    ["name"]=>
    string(7) "setName"
    ["class"]=>
    string(7) "Student"
  }
}

附上一些常用方法,詳細(xì)的可以查看文檔:

ReflectionClass::getMethods     獲取方法的數(shù)組
ReflectionClass::getName        獲取類名
ReflectionClass::hasMethod      檢查方法是否已定義
ReflectionClass::hasProperty    檢查屬性是否已定義
ReflectionClass::isAbstract     檢查類是否是抽象類(abstract)
ReflectionClass::isFinal        檢查類是否聲明為 final
ReflectionClass::isInstantiable 檢查類是否可實(shí)例化
ReflectionClass::newInstance    從指定的參數(shù)創(chuàng)建一個(gè)新的類實(shí)例

2.ReflectionMethod
這個(gè)主要是針對(duì)方法的反射,我們可以簡單執(zhí)行一下:

$stu = new Student();
$ref = new ReflectionClass(Student::class);
$method = $ref->getMethod("setName");
$method->invoke($stu, "john");
var_dump($stu->name);

可以輸出:

john

附上一些常用的方法,詳細(xì)的可以去看看文檔:

ReflectionMethod::invoke        執(zhí)行
ReflectionMethod::invokeArgs    帶參數(shù)執(zhí)行
ReflectionMethod::isAbstract    判斷方法是否是抽象方法
ReflectionMethod::isConstructor 判斷方法是否是構(gòu)造方法
ReflectionMethod::isDestructor  判斷方法是否是析構(gòu)方法
ReflectionMethod::isFinal       判斷方法是否定義 final
ReflectionMethod::isPrivate     判斷方法是否是私有方法
ReflectionMethod::isProtected   判斷方法是否是保護(hù)方法 (protected)
ReflectionMethod::isPublic      判斷方法是否是公開方法
ReflectionMethod::isStatic      判斷方法是否是靜態(tài)方法
ReflectionMethod::setAccessible 設(shè)置方法是否訪問

接下來說一些反射在實(shí)際開發(fā)中比較常見的應(yīng)用。

執(zhí)行私有方法

其實(shí)反射不僅可以執(zhí)行私有方法,還可以讀取私有屬性。這個(gè)主要應(yīng)用在一些設(shè)計(jì)不合理的 SDK 里面,一些很好用的方法和屬性卻不對(duì)外開放。

class Student {
    private    $name;
 
    private function setName($name)
    {
        $this->name = $name;
    }
}

執(zhí)行私有方法:

$stu = new Student();
$ref = new ReflectionClass($stu);
$method = $ref->getMethod("setName");
$method->setAccessible(true);
$method->invoke($stu, "john");

讀取私有屬性:

$stu = new Student();
$ref = new ReflectionClass($stu);
$prop = $ref->getProperty("name");
$prop->setAccessible(true);
$val = $prop->getValue($stu);
var_dump($val);
動(dòng)態(tài)代理

其實(shí) PHP 有魔術(shù)方法,所以實(shí)現(xiàn)動(dòng)態(tài)代理已經(jīng)很簡單了,但是通過魔術(shù)方法來實(shí)現(xiàn)的都不完美,個(gè)人理解最好的實(shí)現(xiàn)應(yīng)該還是 JDK 中的動(dòng)態(tài)代理,基于一個(gè)接口進(jìn)行掃描實(shí)現(xiàn)實(shí)在 PHP 中也可以實(shí)現(xiàn)。我們先來看看動(dòng)態(tài)代理在 JDK 中是怎么使用的:
1.首先定義一個(gè)實(shí)現(xiàn)類的接口,JDK 的動(dòng)態(tài)代理必須基于接口(Cglib則不用)

package com.yao.proxy;
public interface Helloworld {
    void sayHello();
}

2.定義一個(gè)實(shí)現(xiàn)類,這個(gè)類就是要被代理的對(duì)象

package com.yao.proxy;
import com.yao.HelloWorld;

public class HelloworldImpl implements HelloWorld {
    public void sayHello() {
        System.out.print("hello world");
    }
}

3.調(diào)用被代理對(duì)象方法的實(shí)現(xiàn)類

package com.yao.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class MyInvocationHandler implements InvocationHandler{
    private Object target;
    public MyInvocationHandler(Object target) {
        this.target=target;
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("前置工作!");
        Object obj = method.invoke(target,args);
        System.out.println("后置工作!");
        return obj;
    }

4.測(cè)試

package com.yao.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
 
public class Demo {
    public static void main(String[] args) {
        HelloworldImpl realSubject = new HelloworldImpl();
        MyInvocationHandler handler = new MyInvocationHandler(realSubject);
 
        ClassLoader loader = realSubject.getClass().getClassLoader();
        Class[] interfaces = realSubject.getClass().getInterfaces();
      
        HelloworldImpl proxySubject = (HelloworldImpl) Proxy.newProxyInstance(loader, interfaces, handler);
        String hello = proxySubject.sayHello();
    }
}

JDK 的動(dòng)態(tài)代理在底層實(shí)際上是掃描實(shí)現(xiàn)的接口,然后動(dòng)態(tài)生成類的字節(jié)碼文件。PHP 是動(dòng)態(tài)語言,所以可以用 eval 來實(shí)現(xiàn)。
1.定義調(diào)度器接口

interface InvocationHandler  
{  
    function invoke($method, array $arr_args);  
}  

2.動(dòng)態(tài)代理實(shí)現(xiàn)
定義一個(gè)類的 stub:

return new Class($handler,$target) implements %s {  
    private $handler;  
    private $target;
    public function __construct(InvocationHandler $handler, $target) {
        $this->handler = $handler;  
        $this->target = $target;
    }  
    %s  
};

定義一個(gè)方法的 stub:

public function %s(%s) {  
    $args = func_get_args();  
    $method = explode("::", __METHOD__);  
    $this->handler->invoke(new ReflectionMethod($this->target, $method[1]), $args);
}

Proxy 實(shí)現(xiàn):

final class Proxy  
{   
    const CLASS_TEMPLATE = class_stub;      //這里顯示上面定義的,為了方便閱讀
    const FUNCTION_TEMPLATE = function_stub;    //同上
 
    public static function newProxyInstance($target, array $interfaces, InvocationHandler $handler)  {

    }
    protected static function generateClass(array $interfaces) {
       
    }
    protected static function checkInterfaceExists(array $interfaces)  {

    }
}  

其中 newProxyInstancegenerateClass 代碼:

public static function newProxyInstance($target, array $interfaces, InvocationHandler $handler)  {
        self::checkInterfaceExists ($interfaces);
        $code = self::generateClass ($interfaces);
        return eval($code);
    }
protected static function generateClass(array $interfaces)
    {
        $interfaceList = implode(",", $interfaces);
        $functionList = "";
        foreach ($interfaces as $interface) {
            $class = new ReflectionClass ($interface);
            $methods = $class->getMethods();
            foreach ($methods as $method){
                $parameters = [];
                foreach ($method->getParameters() as $parameter){
                    $parameters[] = "$" . $parameter->getName();
                }
                $functionList .= sprintf( self::FUNCTION_TEMPLATE, $method->getName(), implode( ",", $parameters ) );
            }
        }
        return sprintf ( self::CLASS_TEMPLATE, $interfaceList, $functionList );
    }

其中generateClass就是通過反射掃描接口方法,然后根據(jù) stub 模板生成方法拼接成代碼,最后通過 eval 執(zhí)行。

2.測(cè)試

interface Test1{
    public function t1();
}
interface Test2{
    public function t2();
}
class TestImpl implements Test1,Test2{
    public function t1(){
        echo "t1";
    }
    public function t2(){
        echo "t2";
    }
}
$impl = new TestImpl();
class Handler implements InvocationHandler {
    private $target;
    public function __construct($impl){
        $this->target = $impl;
    }
    function invoke(ReflectionMethod $method, array $arr_args){
        echo "前置操作";
        $method->invokeArgs($this->target, $arr_args);
        echo "后置操作";
    }
}

$proxy = Proxy::newProxyInstance($impl, ["Test1", "Test2"], new Handler($impl));
$proxy->t1();

輸出:

前置操作
t1
后置操作
依賴注入

依賴注入是現(xiàn)代化框架中非常常見的一個(gè)功能,它必須和服務(wù)容器結(jié)合使用。用過 Laravel 框架的童鞋應(yīng)該很熟悉,我們可以在任意需要服務(wù)的地方通過類型提示聲明,運(yùn)行時(shí)框架就會(huì)自動(dòng)幫我們注入所需要的對(duì)象。以 Laravel 框架的源碼簡單解析下:
在 Laravel 框架中,我們解析一個(gè)對(duì)象的方法可以這樣:

$obj = App::make(ClassName);

make方法實(shí)際上底層也是調(diào)用了IlluminateContainerContaiern::build($concrete)這個(gè)方法,整理一下源碼就是:

public function build($concrete){
        $reflector = new ReflectionClass($concrete);
        $constructor = $reflector->getConstructor();

        if (is_null($constructor)) {
            return new $concrete;
        }

        $dependencies = $constructor->getParameters();
        $instances = $this->resolveDependencies($dependencies);
        return $reflector->newInstanceArgs($instances);
    }

實(shí)際代碼很簡單,反射類獲取構(gòu)造方法,然后解析依賴參數(shù),傳入執(zhí)行。

歡迎關(guān)我的個(gè)人公眾號(hào):左手代碼

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/26314.html

相關(guān)文章

  • PHP通過反射來得到類,以及一些基本的應(yīng)用

    摘要:發(fā)現(xiàn)大量的使用了反射機(jī)制。下面就來簡單看看一些反射的應(yīng)用獲得反射下面我們來通過這個(gè)反射來得到的私有屬性得到結(jié)果得到這樣我們就可以很輕松的獲得的私有屬性了。最后通過執(zhí)行該方法反射還有很多可用的方法,這里就不一一說了。 這幾天在看laravel框架的核心代碼。發(fā)現(xiàn)大量的使用了反射機(jī)制。下面就來簡單看看一些反射的應(yīng)用 class A { private $_foo = this i...

    BlackHole1 評(píng)論0 收藏0
  • PHP反射機(jī)制

    摘要:反射機(jī)制反射機(jī)制從開始支持,做業(yè)務(wù)開發(fā)的話應(yīng)該很少接觸反射。我的理解就是反射機(jī)制能拿到類里面的屬性方法,和的也可以以上是官方文檔中給出的東西,說實(shí)話我看了感覺沒什么感覺。在容器成員變量中數(shù)組維護(hù)這個(gè)類,反射實(shí)例調(diào)用構(gòu)造函數(shù),獲取返回值。 PHP反射機(jī)制 PHP反射機(jī)制從PHP5開始支持,做業(yè)務(wù)開發(fā)的話應(yīng)該很少接觸反射。我其實(shí)也是接觸不多,最近在學(xué)習(xí)laravel的優(yōu)雅,就接觸了到它其中...

    URLOS 評(píng)論0 收藏0
  • Laravel深入學(xué)習(xí)2 - 控制反轉(zhuǎn)容器

    摘要:控制反轉(zhuǎn)容器控制反轉(zhuǎn)使依賴注入變得更加便捷。有瑕疵控制反轉(zhuǎn)容器是實(shí)現(xiàn)的控制翻轉(zhuǎn)容器的一種替代方案。容器的獨(dú)立使用即使沒有使用框架,我們?nèi)匀豢梢栽陧?xiàng)目中使用安裝組件來使用的控制反轉(zhuǎn)容器。在沒有給定任何信息的情況下,容器是無法實(shí)例化相關(guān)依賴的。 聲明:本文并非博主原創(chuàng),而是來自對(duì)《Laravel 4 From Apprentice to Artisan》閱讀的翻譯和理解,當(dāng)然也不是原汁原味...

    worldligang 評(píng)論0 收藏0
  • PHP核心技術(shù)與最佳實(shí)踐(第一章 面向?qū)ο笏枷氲暮诵母拍睿?/b>

    摘要:現(xiàn)代的面向?qū)ο蟮乃枷氩粡?qiáng)調(diào)為真實(shí)世界建模變得更加理性化一些,把目標(biāo)放在解耦上。各種語言中的多態(tài)多態(tài)確切的含義是同一類的對(duì)象收到相同消息時(shí),會(huì)得到不同的結(jié)果。小結(jié)本章主要介紹面向?qū)ο笏枷氲某绦虻慕M成元素類和對(duì)象。 第一章 面向?qū)ο笏枷氲暮诵母拍?showImg(https://segmentfault.com/img/bVNfjM?w=673&h=334); showImg(https:...

    dreamGong 評(píng)論0 收藏0
  • 從yii2框架中的di容器源碼中了解反射的作用

    摘要:反射簡介參考官方簡介的話,具有完整的反射,添加了對(duì)類接口函數(shù)方法和擴(kuò)展進(jìn)行反向工程的能力。此外,反射提供了方法來取出函數(shù)類和方法中的文檔注釋。 反射簡介 參考官方簡介的話,PHP 5 具有完整的反射 API,添加了對(duì)類、接口、函數(shù)、方法和擴(kuò)展進(jìn)行反向工程的能力。 此外,反射 API 提供了方法來取出函數(shù)、類和方法中的文檔注釋。 YII2框架中示例 對(duì)于yii2框架,應(yīng)該都知道di容器,...

    dantezhao 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<