国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

怎么從0到1實(shí)現(xiàn)一個(gè)PHP框架?

這篇具有很好參考價(jià)值的文章主要介紹了怎么從0到1實(shí)現(xiàn)一個(gè)PHP框架?。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

寫在前面

本人開發(fā)的框架在2021年年初開發(fā)完成,后面沒有再做過任何維護(hù)和修改。是僅供大家參考交流的學(xué)習(xí)項(xiàng)目,請勿使用在生產(chǎn)環(huán)境,也勿用作商業(yè)用途。

框架地址:
https://github.com/yijiebaiyi/fast_framework

整體思路

開發(fā)一款web框架,首先要考慮這個(gè)框架的整體運(yùn)行架構(gòu),然后具體到那些功能的擴(kuò)展。那么我開發(fā)框架的時(shí)候想的是,精簡為主,實(shí)用為主。主要功能需要包括入口文件、路由解析、異常處理、日志記錄、ORM、緩存、類依賴注入。

入口文件

入口文件需要定義全局變量,主要是核心框架文件的所在路徑,然后,通過include_once引入框架核心類文件,初始化框架進(jìn)行初始化操作。

<?php

define("FAST_PATH", $_SERVER["DOCUMENT_ROOT"] . DIRECTORY_SEPARATOR . "fast");

// 初始化
include_once FAST_PATH . DIRECTORY_SEPARATOR . "App.php";
(new \fast\App())->init();

應(yīng)用核心類

應(yīng)用核心類主要是用來注冊類的自動加載、加載環(huán)境變量文件、注冊錯(cuò)誤異常以及注冊路由。下面是應(yīng)用初始化init方法。

    public function init()
    {
        if (false === $this->isInit) {
            define("DOCUMENT_ROOT", $_SERVER["DOCUMENT_ROOT"]);
            define("ROOT_PATH", $_SERVER["DOCUMENT_ROOT"]);
            define("RUNTIME_PATH", $_SERVER["DOCUMENT_ROOT"] . DIRECTORY_SEPARATOR . "runtime");
            define("APP_PATH", $_SERVER["DOCUMENT_ROOT"]);

            // 注冊自動加載
            require_once FAST_PATH . DIRECTORY_SEPARATOR . "Autoload.php";
            (new Autoload())->init();

            // 注冊配置
            (new Config())->init();

            // 加載env
            (new Env())->init();

            // 注冊錯(cuò)誤和異常
            (new Exception())->init();
            (new Error())->init();
            (new Shutdown())->init();

            // 檢驗(yàn)運(yùn)行環(huán)境
            $this->validateEnv();

            // 注冊路由
            (new Route())->init();

            $this->isInit = true;
        }
    }

上面初始化的方法中,我們需要先判斷框架是否已經(jīng)初始化,如果已經(jīng)初始化則不需要再進(jìn)行操作了。init方法中所涉及到的類都在框架核心文件根目錄下面,需要注意的是,一定要先注冊自動加載,不然使用new 關(guān)鍵字生成對象就會報(bào)錯(cuò)。下面是自動加載類的自動加載方法。

    public function init()
    {
        if (false === $this->isInit) {
            spl_autoload_register(array($this, 'autoload'));

            $this->isInit = true;
        }
    }

    /**
     * @var array 類加載次
     */
    private static array $loadedClassNum = [];

    /**
     * 自動加載
     * @param $name
     * @throws Exception
     */
    public static function autoload($name): void
    {
        if (trim($name) == '') {
            throw new Exception("No class for loading");
        }

        $file = self::formatClassName($name);

        if (isset(self::$loadedClassNum[$file])) {
            self::$loadedClassNum[$file]++;
            return;
        }
        if (!$file || !is_file($file)) {
            return;
        }
        // 導(dǎo)入文件
        include $file;

        if (empty(self::$loadedClassNum[$file])) {
            self::$loadedClassNum[$file] = 1;
        }
    }

    /**
     * 返回全路徑
     * @param $className
     * @return string
     */
    private static function formatClassName($className): string
    {
        return $_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . $className . '.php';
    }

使用PHP提供的spl_autoload_register自動加載器函數(shù),注冊autoload方法實(shí)現(xiàn)自動加載,可以看到我們自動加載的類必須都在項(xiàng)目根目錄下才可以實(shí)現(xiàn)。這是一個(gè)簡單的約定。

加載配置

我們知道php使用include 導(dǎo)入文件是可以獲取到文件的返回值的(如果有的話),所以使用php文件返回一個(gè)數(shù)組來實(shí)現(xiàn)項(xiàng)目的配置文件,框架里面支持默認(rèn)的config.php文件,以及額外用戶可以自定義的配置:extra.php。這個(gè)也是我們約定好的。

配置文件示例代碼config.php:

<?php

return [
    "Cache" => [
        "default" => "redis",
        "redis" => [
            "master" => [
                "pconnect" => false,
                "host" => "localhost",
                "port" => 6379,
                "timeout" => 0,
            ],
        ],
    ],
    "Log" => [
        "default" => "file",
        "file" => [
            "path" => RUNTIME_PATH
        ],
    ]
];

引入配置文件的關(guān)鍵代碼:

    /**
     * 加載配置
     * @param $filename
     */
    private static function addConfig($filename): void
    {
        $configArr = include_once($filename);
        if (is_array($configArr)) {
            self::$configs = Arr::arrayMergeRecursiveUnique(self::$configs, $configArr);
        }
    }

    /**
     * 導(dǎo)入配置
     * @param $paths
     */
    private static function importConfig($paths): void
    {
        foreach ($paths as $path) {
            self::addConfig($path);
        }
    }

加載環(huán)境變量

環(huán)境變量文件,我們默認(rèn)的就是項(xiàng)目根目錄的.env文件。.env文件配置項(xiàng)是標(biāo)準(zhǔn)的*.ini類型配置文件的書寫方式,且.env文件里面的配置項(xiàng)不區(qū)分大小寫,小寫配置項(xiàng)最終會被轉(zhuǎn)化成大寫。.env文件的加載使用php的函數(shù)parse_ini_file來實(shí)現(xiàn):

    /**
     * 加載環(huán)境變量定義文件
     * @param string $file 環(huán)境變量定義文件
     * @return void
     */
    public static function load(string $file): void
    {
        $env = parse_ini_file($file, true) ?: [];
        static::set($env);
    }

框架支持環(huán)境變量的寫入、讀取和檢測。

錯(cuò)誤和異常

異常信息抓取到之后,我們將他格式化處理,主要記錄異常碼、異常文件和所在行號。然后將異常寫入日志。(注意,如果是生產(chǎn)模式,需要關(guān)閉錯(cuò)誤顯示)

    public static function handler($exception)
    {
        // 設(shè)置http狀態(tài)碼,發(fā)送header
        if (in_array($exception->getCode(), array_keys(Http::$httpStatus))) {
            self::$httpCode = $exception->getCode();
        } else {
            self::$httpCode = 500;
        }
        Http::sendHeader(self::$httpCode);

        // 異常信息格式化輸出
        $echoExceptionString = "<b>message</b>:  {$exception->getMessage()}<br/>" .
            "<b>code</b>:  {$exception->getCode()}<br/>" .
            "<b>file</b>:  {$exception->getFile()}<br/>" .
            "<b>line</b>:  {$exception->getLine()}<br/>";

        $serverVarDump = Str::dump(false, $_SERVER);
        $postVarDump = Str::dump(false, $_POST);
        $filesVarDump = Str::dump(false, $_FILES);
        $cookieVarDump = Str::dump(false, $_COOKIE);

        $logExceptionString = "message:  {$exception->getMessage()}" . PHP_EOL .
            "code:  {$exception->getCode()}" . PHP_EOL .
            "file:  {$exception->getFile()}" . PHP_EOL .
            "line:  {$exception->getLine()}" . PHP_EOL .
            "\$_SERVER:  {$serverVarDump}" . PHP_EOL .
            "\$_POST:  {$postVarDump}" . PHP_EOL .
            "\$_COOKIE:  {$cookieVarDump}" . PHP_EOL .
            "\$_FILES:  {$filesVarDump}";
        Log::write($logExceptionString, Log::ERROR);

        // debug模式將錯(cuò)誤輸出
        if (static::isDebugging()) {
            if (self::$isJson) {
                echo Json::encode(["message" => $exception->getMessage(), "code" => 0]);
                App::_end();
            } else {
                echo $echoExceptionString;
            }
        }
    }

路由分發(fā)

路由的實(shí)現(xiàn)思路是:我們根據(jù)請求的地址,截取到請求的路徑信息(根據(jù)PHP全局變量$_SERVER[‘PATH_INFO’]獲取),根據(jù)路徑信息的格式,定位到某個(gè)控制器類的某個(gè)方法,然后將其觸發(fā)。實(shí)現(xiàn)代碼:

    public function distribute()
    {
        // 解析path_info
        if (isset($_SERVER['PATH_INFO'])) {
            $url = explode('/', trim($_SERVER['PATH_INFO'], "/"));
            if (count($url) < 3) {
                $url = array_pad($url, 3, "index");
            }
        } else {
            $url = array_pad([], 3, "index");
        }

        // 獲取類名和方法名
        $className = self::formatClassName($url);
        $actionName = self::formatActionName($url);

        if (!class_exists($className)) {
            throw new Exception("the controller is not exist: {$className}", 404);
        }

        $class = new $className();

        if (!is_callable([$class, $actionName])) {
            throw new Exception("the action is not exist: {$className} -> {$actionName}", 404);
        }

        if (!$class instanceof Controller) {
            throw new Exception("the controller not belongs to fast\\Controller: {$className}", 403);
        }

        // 將請求分發(fā)
        $class->$actionName();
    }

實(shí)現(xiàn)緩存

框架中的緩存、日志、ORM都是使用適配器模式。即定義一個(gè)抽象類,抽象類中定義若干抽象方法。這樣的話,繼承了抽象類的方法必須要實(shí)現(xiàn)這些抽象方法。我們就可以通過統(tǒng)一的入口去根據(jù)配置去調(diào)用對應(yīng)的適配器類了。

其中緩存適配了Redis、Memcache以及Memcached三種。開發(fā)者可以在config.php配置文件中自行配置。

緩存主要實(shí)現(xiàn)了將數(shù)據(jù)寫入緩存和獲取緩存數(shù)據(jù)兩個(gè)方法,我們以redis為例,redis緩存主要是使用redis字符串存儲結(jié)構(gòu),使用set和get方法來實(shí)現(xiàn)。

    public function get($key, &$time = null, &$expire = null)
    {
        $_key = $this->makeKey($key);
        $res = $this->slaveObj->get($_key);
        if (is_null($res) || false === $res) {
            return null;
        }

        $res = unserialize($res);
        if ($res && isset($res['value'])) {
            $time = $res['time'];
            $expire = $res['expire'];
            return $res['value'];
        }

        return null;
    }

    public function set($key, $value = null, $expire = 3600): bool
    {
        return $this->masterObj->set($this->makeKey($key), serialize($this->makeValue($value, $expire)), $expire);
    }

前面的代碼只是適配器的實(shí)現(xiàn),那么我們怎么調(diào)用適配器類中的方法呢。我這邊想到的是,在框架核心代碼根目錄創(chuàng)建一個(gè)緩存文件類,實(shí)現(xiàn)一個(gè)單例,通過配置來讀取我們要使用什么類型的緩存(即使用哪個(gè)適配器類),配置中配置項(xiàng)是緩存適配器類的類名稱,讀取到了我們就加載他。具體實(shí)現(xiàn)代碼:

    public static function instance($type = "default"): CacheDriver
    {
        if ($type === "default") {
            $_type = Config::get("Cache.default");
        } else {
            $_type = $type;
        }

        if (!$_type) {
            throw new Exception("The type can not be set to empty!");
        }

        if (!isset(self::$_instance[$_type])) {
            $conf = Config::get("Cache.{$_type}");

            if (empty($conf)) {
                throw new Exception("The '{$_type}' type cache config does not exists!");
            }

            $class = self::getNamespace() . "\\" . ucfirst($_type);
            $obj = new $class();

            if (!$obj instanceof CacheDriver) {
                throw new Exception("The '{$class}' not instanceof CacheDriver!");
            }

            $obj->init($conf);
            self::$_instance[$_type] = $obj;

        } else {
            $obj = self::$_instance[$_type];
        }

        return $obj;
    }

注:日志以及ORM的實(shí)現(xiàn)方法和緩存的實(shí)現(xiàn)類似,也是通過實(shí)現(xiàn)一個(gè)適配器,然后通過加載配置中定義的適配器類來加載。

實(shí)現(xiàn)完了之后我們測試一下:

設(shè)置:

        $cacheObj = Cache::instance('redis');
        $setRes = $cacheObj->setModuleName("user")->set(["id" => 1], ["name" => "ZhangSan"], 1000);
        if ($setRes) {
            echo "設(shè)置成功";
        } else {
            echo "設(shè)置失敗";
        }

獲?。?/p>

        $cacheObj = Cache::instance('redis');
        $res = $cacheObj->setModuleName("user")->get(["id" => 1], $time, $expire);
        var_dump($res, $time, $expire);

實(shí)現(xiàn)日志

日志的實(shí)現(xiàn)比較簡單,主要值實(shí)現(xiàn)了日志的寫入功能,通過php函數(shù)file_put_contents實(shí)現(xiàn)寫入文件。當(dāng)然也可以使用別的方法來實(shí)現(xiàn)。
相關(guān)代碼:

public function write(string $message, string $type)
    {
        if (empty($message)) {
            trigger_error('$message dose not empty! ');

            return false;
        }

        if (empty($type)) {
            trigger_error('$type dose not empty! ');

            return false;
        }

        $path = APP_PATH . DIRECTORY_SEPARATOR . 'runtime' . DIRECTORY_SEPARATOR . 'logs' . DIRECTORY_SEPARATOR . $type . '/' . date('Ym/d') . '.log';

        $mark = "\n\n===========================================================================\n";
        $mark .= 'time:' . date('Y/m/d H:i:s') . "\n";

        return \fast\util\File::write($mark . $message, $path, (FILE_APPEND | LOCK_EX));
    }
    public static function write($content, $path, $flags = 0)
    {
        $path = trim($path);
        if (empty($path)) {
            trigger_error('$path must to be set!');

            return false;
        }

        $dir = dirname($path);
        if (!self::exists($dir)) {
            if (false == self::mkdir($dir)) {
                trigger_error('filesystem is not writable: ' . $dir);

                return false;
            }
        }
        $path = str_replace("http://", "/", $path);

        return file_put_contents($path, $content, ((empty($flags)) ? (LOCK_EX) : $flags));
    }

應(yīng)用層調(diào)用:

Log::write("這是一條info類型的log", Log::INFO);

實(shí)現(xiàn)操作數(shù)據(jù)庫

數(shù)據(jù)庫目前只實(shí)現(xiàn)了Mysql,如果需要支持別的數(shù)據(jù)庫,只需要新增適配器即可。區(qū)別于緩存的實(shí)現(xiàn),數(shù)據(jù)庫使用接口interface作為適配器的約定。

mysql的實(shí)現(xiàn)主要依賴mysqli庫,它對mysql庫做了優(yōu)化,防注入更完善一些。CURD的具體實(shí)現(xiàn)思路是,先獲取要處理的數(shù)據(jù),最終拼接成sql來執(zhí)行。

注:鏈?zhǔn)秸{(diào)用通過方法返回$this來實(shí)現(xiàn)

簡單看一下select查詢的實(shí)現(xiàn):

    public function select()
    {
        $this->checkMysqlOperate("table_empty");
        empty($this->_fields) && $this->_fields = "*";

        $sql = "SELECT {$this->_fields} FROM {$this->_table}";
        !empty($this->_where) && $sql .= " WHERE {$this->_where}";
        !empty($this->_order) && $sql .= " ORDER BY {$this->_order}";
        !empty($this->_group) && $sql .= " GROUP BY {$this->_group}";
        !empty($this->_limit) && $sql .= " LIMIT {$this->_offset}, {$this->_limit}";

        $this->_sql = $sql;
        $mysqliResult = mysqli_query($this->_connection, $this->_sql);
        if (false === $mysqliResult) {
            $this->_error = mysqli_error($this->_connection);
            return false;
        }
        return mysqli_fetch_all($mysqliResult, MYSQLI_ASSOC);
    }

我們在應(yīng)用層調(diào)用一下select:

  $dbInstance = Db::getInstance();
  $result = $dbInstance->table('student')->where('SId in (01, 02, 13)')->order("SId DESC")->select();

update:

  $dbInstance = Db::getInstance();
  $dbInstance->table('student');
  $dbInstance->where(['Sid' => '01']);
  $result = $dbInstance->update($data);

數(shù)據(jù)驗(yàn)證器

數(shù)據(jù)驗(yàn)證器主要是用來驗(yàn)證數(shù)據(jù)是否符合我們的規(guī)范,可以用來驗(yàn)證表單數(shù)據(jù),也可以用來驗(yàn)證業(yè)務(wù)數(shù)據(jù)。

主要實(shí)現(xiàn)是列舉所有的驗(yàn)證規(guī)則依次校驗(yàn),主要有這些規(guī)則校驗(yàn):必傳校驗(yàn)、類型校驗(yàn)、字符校驗(yàn)、數(shù)字校驗(yàn)、正則校驗(yàn)。

主要實(shí)現(xiàn)代碼:

    public function check(array $data, array $rules): self
    {
        foreach ($rules as $rule => $message) {
            $dataRule = explode(".", $rule);
            if (count($dataRule) < 2) {
                continue;
            }

            // 必傳校驗(yàn)
            if ($dataRule[1] == "required" && !isset($data[$dataRule[0]])) {
                array_push($this->errors, $message);
                continue;
            }

            if (!isset($data[$dataRule[0]])) {
                continue;
            }

            // 類型校驗(yàn)
            if (in_array($dataRule[1], $this->typeCheckName)) {
                if (false === self::typeCheck(strval($dataRule[1]), $data[$dataRule[0]])) {
                    array_push($this->errors, $message);
                    continue;
                }
            }

            // 字符校驗(yàn)
            if (in_array($dataRule[1], $this->stringCheckName) && isset($dataRule[2])) {
                if (false === self::stringCheck(strval($dataRule[1]), $dataRule[2], $data[$dataRule[0]])) {
                    array_push($this->errors, $message);
                    continue;
                }
            }

            // 數(shù)字校驗(yàn)
            if (in_array($dataRule[1], $this->operatorCheckName) && isset($dataRule[2])) {
                if (false === self::operatorCheck(strval($dataRule[1]), $dataRule[2], $data[$dataRule[0]])) {
                    array_push($this->errors, $message);
                    continue;
                }
            }

            // 正則校驗(yàn)
            if (in_array($dataRule[1], array_keys($this->pregCheckRules))) {
                if (false === self::pregCheck(strval($dataRule[1]), $data[$dataRule[0]])) {
                    array_push($this->errors, $message);
                    continue;
                }
            }
        }
        return $this;
    }

字符傳校驗(yàn)部分代碼:

    public function stringCheck(string $rule, $value, $dataValue): bool
    {
        $flag = true;
        switch ($rule) {
            case "max":
                strlen($dataValue) > $value && $flag = false;
                break;
            case "min":
                strlen($dataValue) < $value && $flag = false;
                break;
            case "length":
                strlen($dataValue) != $value && $flag = false;
                break;
            case "in":
                $value = explode(",", $value);
                !in_array($dataValue, $value) && $flag = false;
                break;
            case "notIn":
                $value = explode(",", $value);
                in_array($dataValue, $value) && $flag = false;
                break;
        }
        return $flag;
    }

業(yè)務(wù)層這樣調(diào)用:

    public function testValidate()
    {
        $validate = new ValidateData();
        $data = [
            "age" => 17,
            "weight" => "50公斤",
            "name" => "ZhangSan",
            "country" => "這里是中國abc",
            "sex" => "未知",
            "mobile" => "11098186452",
        ];

        $rules = [
            "age.required" => "請輸入年齡",
            "email.required" => "請輸入郵箱",
            "age.gt.18" => "年齡必須大于18",
            "weight.float" => "體重必須為浮點(diǎn)數(shù)",
            "name.max.6" => "姓名最大長度為6",
            "country.alphaNum" => "國家必須為數(shù)字或者字母",
            "sex.in.男,女" => "性別必須是男或者女",
            "mobile.mobile" => "手機(jī)號碼不合法",
        ];
        $validate->check($data, $rules);

        var_dump($validate->getErrors());
    }

實(shí)現(xiàn)容器依賴注入

首先我們先了解概念??蚣苤械娜萜髦傅氖鞘裁??什么是依賴注入?

容器(當(dāng)前所指)是一個(gè)用于管理和存儲應(yīng)用程序中各種對象的工具。它允許你注冊、創(chuàng)建和解析對象,以及管理它們之間的依賴關(guān)系。當(dāng)前框架中的容器通常使用關(guān)聯(lián)數(shù)組來存儲對象和服務(wù)。

依賴注入是一種設(shè)計(jì)模式,它允許你將一個(gè)對象的依賴關(guān)系傳遞給它,而不是在對象內(nèi)部直接創(chuàng)建或管理依賴關(guān)系。
這可以使代碼更加可測試、可維護(hù)和可擴(kuò)展,因?yàn)樗鼘ο蟮囊蕾囆越怦?,并使它們更容易替換和修改。
依賴注入通常通過構(gòu)造函數(shù)注入、方法注入或?qū)傩宰⑷雭韺?shí)現(xiàn)。
在當(dāng)前框架中,依賴注入和容器一起使用,容器負(fù)責(zé)實(shí)例化和解析對象,并自動注入它們的依賴關(guān)系。

那么如何實(shí)現(xiàn)呢?通過php的反射,來獲取類的相關(guān)信息來解決依賴。

我們從容器中拿一個(gè)服務(wù)對象,如果沒有拿到,則需要創(chuàng)建。創(chuàng)建的時(shí)候通過下面幾步我們來解決依賴。

  1. 根據(jù)類名獲取目標(biāo)類(實(shí)際是反射類)
$reflection = new \ReflectionClass($className)
  1. 進(jìn)一步獲取目標(biāo)類的構(gòu)造方法(實(shí)際是構(gòu)造方法類)
$reflection->getConstructor()
  1. 獲取構(gòu)造方法所需參數(shù)類(是一個(gè)數(shù)組)
$constructorParameters = $constructor->getParameters()
  1. 循環(huán)所需參數(shù),如果參數(shù)沒有默認(rèn)值,則是一個(gè)服務(wù)對象,我們繼續(xù)從容器中獲取,直到解決所有的依賴。
foreach ($constructorParameters as $param) {
    if (version_compare(PHP_VERSION, '5.6.0', '>=') && $param->isVariadic()) {
        break;
    } elseif ($param->isDefaultValueAvailable()) {
        $dependencies[] = $param->getDefaultValue();
    } else {
        $c = $param->getClass();
        $dependencies[] = $this->get($c->getName(), $this->_params[$c->getName()] ?? []);
    }
}

注:請避免出現(xiàn)循環(huán)嵌套,否則會出現(xiàn)未知問題

創(chuàng)建的完整代碼:

    public function build(string $className, array $params = []): ?object
    {
        if (isset($this->_reflections[$className])) {
            $reflection = $this->_reflections[$className];
        } else {
            try {
                $reflection = new \ReflectionClass($className);
            } catch (ReflectionException $exception) {
                throw new Exception("Failed to reflect class " . $className . ", error: " . $exception->getMessage());
            }
            $this->_reflections[$className] = $reflection;
        }

        if (!$reflection->isInstantiable()) {
            throw new Exception("Is not instantiable:" . $reflection->name);
        }

        $dependencies = [];
        $constructor = $reflection->getConstructor();
        if ($constructor !== null) {
            $constructorParameters = $constructor->getParameters();
            foreach ($constructorParameters as $param) {
                if (version_compare(PHP_VERSION, '5.6.0', '>=') && $param->isVariadic()) {
                    break;
                } elseif ($param->isDefaultValueAvailable()) {
                    $dependencies[] = $param->getDefaultValue();
                } else {
                    $c = $param->getClass();
                    $dependencies[] = $this->get($c->getName(), $this->_params[$c->getName()] ?? []);
                }
            }
        }

        $this->_dependencies[$className] = Arr::arrayMergeBase($dependencies, $params);
        $object = $reflection->newInstanceArgs($this->_dependencies[$className]);
        $this->_objects[$className] = $object;
        return $object;
    }
}

解決完依賴,我們就把改服務(wù)存入容器中。

業(yè)務(wù)層調(diào)用:

    $container = new Container();
    $container->set("app\service\Group", [123]);
    $container->set("app\service\User");
    $container->set("app\service\UserList");
    $group = $container->get("app\service\Group");
    $userList = $container->get("app\service\UserList");
    $group->getA();
    $userList->getUserList();

Group.php:

<?php
namespace app\service;

class Group
{
    public static $a = 0;

    function __construct($a =1)
    {
        static::$a = $a;
    }

    public function getA()
    {
        echo self::$a;
    }
}

User.php:

<?php
namespace app\service;

class User
{
    public function __construct(Group $group)
    {

    }

    function user()
    {

    }
}

UserList.php:

<?php
namespace app\service;

class UserList
{
    public function __construct(User $user)
    {

    }

    public function getUserList()
    {
        echo "this is the user-list";
    }
}

尾聲

至此,這款簡易的php框架的實(shí)現(xiàn)過程就介紹完了。更多詳細(xì)的內(nèi)容請異步:

https://github.com/yijiebaiyi/fast_framework

這里有詳細(xì)的代碼示例和完整的實(shí)現(xiàn)過程。文章來源地址http://www.zghlxwxcb.cn/news/detail-705226.html

到了這里,關(guān)于怎么從0到1實(shí)現(xiàn)一個(gè)PHP框架?的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 用php語言寫一個(gè)chatgpt3.5模型的例子

    當(dāng)然可以!使用PHP語言調(diào)用OpenAI API與ChatGPT-3.5模型進(jìn)行交互。首先,確保你已經(jīng)安裝了PHP 7.2或更新版本,并具備可用的OpenAI API密鑰。 下面是一個(gè)基本的PHP示例,展示了如何使用OpenAI API與ChatGPT-3.5模型進(jìn)行對話: 以上是一個(gè)基本的例子,你可以根據(jù)自己的需求進(jìn)行修改和擴(kuò)展

    2024年02月13日
    瀏覽(22)
  • 【周末閑談】“PHP是最好的語言”這個(gè)梗是怎么來的?

    【周末閑談】“PHP是最好的語言”這個(gè)梗是怎么來的?

    個(gè)人主頁:【??個(gè)人主頁】 系列專欄:【??周末閑談】 ?第一周 二進(jìn)制VS三進(jìn)制 ?第二周 文心一言,模仿還是超越? ?第二周 暢想AR 突然發(fā)現(xiàn)已經(jīng)很久沒有更新周末閑談這個(gè)專欄了,不能在擺爛下去了。ψ(`?′)ψ “PHP是最好的語言”,經(jīng)常被用來嘲諷程序員技術(shù)較差

    2024年02月08日
    瀏覽(27)
  • php怎么實(shí)現(xiàn)時(shí)間差

    php實(shí)現(xiàn)時(shí)間差的方法:1、通過strtotime函數(shù)將兩個(gè)日期轉(zhuǎn)換為時(shí)間戳;2、通過“$enddate-$startdate”公式將兩個(gè)時(shí)間戳相減;3、將時(shí)間差“$diff_seconds”除以86400,并使用“floor()”函數(shù)向下舍入為最接近的整數(shù)即可獲得相差天數(shù)。 php怎么實(shí)現(xiàn)時(shí)間差? php求兩個(gè)給定日期的時(shí)間差:

    2024年02月08日
    瀏覽(25)
  • PHP接口自動化測試框架實(shí)現(xiàn)

    我們來看一個(gè)簡單的PHP實(shí)現(xiàn)的超簡單的接口。 說明: 首先,它是一個(gè)POST接口。它需要兩個(gè)參數(shù):raid 和 mid。 然后,判斷raid 和 mid 是否為空,為空返回:參數(shù)錯(cuò)誤。 最后,調(diào)用 enlist_model 模型,通過? get_enlist_by_raid_mid 方法查詢是否為空,如果不為空返回:你已經(jīng)報(bào)過名了。

    2024年02月14日
    瀏覽(20)
  • 6.php開發(fā)-個(gè)人博客項(xiàng)目&Tp框架&路由訪問&安全寫法&歷史漏洞

    6.php開發(fā)-個(gè)人博客項(xiàng)目&Tp框架&路由訪問&安全寫法&歷史漏洞

    目錄 知識點(diǎn) php框架——TP URL訪問 Index.php-放在控制器目錄下 ?編輯 Test.php--要繼承一下 帶參數(shù)的—————— 加入數(shù)據(jù)庫代碼 --不過濾 --自己寫過濾 --手冊(官方)的過濾 用TP框架找漏洞: 如何判斷網(wǎng)站是thinkphp? 黑盒: 白盒: php總結(jié) ? 1-基于TP框架入門安裝搭建使用

    2024年01月25日
    瀏覽(20)
  • 推薦一個(gè)日歷轉(zhuǎn)換開源工具庫,支持C#、Java、PHP等主流的語言

    推薦一個(gè)日歷轉(zhuǎn)換開源工具庫,支持C#、Java、PHP等主流的語言

    日歷對我們來說,最熟悉的就是陽歷和農(nóng)歷,在中國每年都有固定的節(jié)日、節(jié)氣、中國特有傳統(tǒng)節(jié)日,有些節(jié)日是固定的,但是節(jié)氣這些都需要我們經(jīng)過一定規(guī)則換算出來。 所以,今天給大家推薦一個(gè)開源庫,它支持陽歷、陰歷、佛歷和道歷的日歷轉(zhuǎn)換,可以滿足我們的所有

    2024年02月06日
    瀏覽(22)
  • 短視頻矩陣系統(tǒng)源碼開發(fā)搭建技術(shù)解析-PHP語言

    短視頻矩陣系統(tǒng)源碼開發(fā)搭建技術(shù)解析-PHP語言

    一、系統(tǒng)架構(gòu) 整個(gè)短視頻矩陣系統(tǒng)大概分為以下幾個(gè)模塊: 1.多平臺賬號管理 支持抖音、快手、小紅書、西瓜、頭條視頻號等多平臺賬號管理。 2.視頻管理模塊 支持視頻批量上傳、批量剪輯、文字轉(zhuǎn)語音,特效等功能配置 3.推薦算法模塊 推薦算法模塊主要用來推薦用戶感興

    2024年02月07日
    瀏覽(27)
  • 第27天:安全開發(fā)-PHP應(yīng)用&TP框架&路由訪問&對象操作&內(nèi)置過濾繞過&核心漏洞

    第27天:安全開發(fā)-PHP應(yīng)用&TP框架&路由訪問&對象操作&內(nèi)置過濾繞過&核心漏洞

    1.TP框架-開發(fā)-配置架構(gòu)路由MVC模型 參考:https://www.kancloud.cn/manual/thinkphp5_1 配置架構(gòu)-導(dǎo)入使用 路由訪問-URL訪問 數(shù)據(jù)庫操作-應(yīng)用對象 文件上傳操作-應(yīng)用對象 前端頁面渲染-MVC模型 1.TP框架-安全-不安全寫法版本過濾繞過 1.內(nèi)置代碼寫法 不合要求的代碼寫法-ThinkPHP5-自寫 2.框架

    2024年04月25日
    瀏覽(30)
  • 淺談PHP框架中類成員方法的類類型形參是怎么利用ReflectionClass反射類自動實(shí)例化的(應(yīng)該是全網(wǎng)首發(fā))

    1. 或許是全網(wǎng)首發(fā),我翻過很多文章,從未有一個(gè)博主講過這個(gè)東西,很多博主只講了IOC、DI和反射機(jī)制的常見用法,因類類型形參反射的巧妙用法有相當(dāng)高的難度和學(xué)習(xí)盲區(qū),所以從未有人講過類類型的形參它怎么就被自動實(shí)例化的。 2. 在Laravel框架,或者是其它框架中,類

    2024年02月06日
    瀏覽(25)
  • HTML+PHP+MYSQL實(shí)現(xiàn)一個(gè)簡單的留言板

    HTML+PHP+MYSQL實(shí)現(xiàn)一個(gè)簡單的留言板

    提示:這里可以添加系列文章的所有文章的目錄,目錄需要自己手動添加 大家好,下面將為大家展示 基于HTML PHP MYSQL的留言板的設(shè)計(jì)與實(shí)現(xiàn)過程,適合初學(xué)者點(diǎn)擊觀看,以下我將會以筆者自稱! 提示:寫完文章后,目錄可以自動生成,如何生成可參考右邊的幫助文檔 提示:

    2024年02月04日
    瀏覽(22)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包