Swoft| Swoft Frame Component Transformation

date: 2018-3-21 13:22:16
Title: Swoft| Swoft framework modular transformation
Description: Swoft Framework Upgrade from Monomer Application to Component Transformation

After more than a year of development, the Swoft framework has become more and more complete and complex. During its initial stageMonomer application, has been unable to support the rapid development of the project, so the development team set up for the 1.0-beta version years agoModular transformationThe reconstruction scheme of.

Content overview:

  • Principle of Component: Basic Knowledge of PHP Package Management
  • Component Scheme: Component Implementation Scheme from Mature Frameworks such as laravel/symfony
  • Component implementation of Swoft framework

Principle of componentization

A Problem Always to be Solved in Programming:Code reuseGood code, basic requirements areCorrect, can get the expected results, fewer bugs. Language layer code reuse solution, usually calledPackage management(orDependency management). Popular programming languages all provide good tool chain support for package management:

  • A command line tool to get/manage packages, such as php’scomposer, python’s pip, js’s npm, java’s maven, go’sgo get
  • A package management configuration file that describes the packages that need to be used (depending on), such as composer in PHPcomposer.josnNpm use of jspackage.json
  • A website browsing packages, used to view package information, such as php’spackgistPypi of python, etc

In this way, when we need different functions, we can check whether there are packages that already provide similar functions.Don’t build wheels again, stand on the shoulders of giants..

Back in PHP, how is package management implemented in PHP?

  • Namespace

The first basic concept to know isNamespace. Namespaces are introduced toResolve conflicts of the same name-2 packages have classes with the same name, and when they are used at the same time, there will be a prompt that the classes are repeatedly defined. After using namespaces, there will be no conflict because different packages have different namespaces.

// 如果需要在同一个文件中使用相同名字的类, 使用别名
use A\Far;
use B\Far as BFar;
  • Auto load & PSR4

The second basic concept to know isautoloading. PHP’s most basic (or primitive) method of reusing code:include/include_one/require/require_onceBut thanks to PHPSPL libraryhit the targetspl_autoload_register()Methods, there is now a more elegant way to reuse code-auto-loading. The auto-loading specification has also undergone a period of upgrading and polishing. The latest isPSR4 standard.

There is a good tutorial on automatic loading:The 5-1 SPL uses the spl_autoload_register function to load the class (10:03)

Package Management in composer

Once you know the basic knowledge, you can master how to use the tools.Package Management in composerAccording tocomposer.jsonIn the fileautoload / require / require-devConfiguration items to manage.

autoloadThe definition of automatic loading, the code of the project itself, should also be organized according to the specification of package management, such asJson configuration file for Swoft:

...
    "autoload": {
        "psr-4": {
            "App\\": "app/"
        },
        "files": [
            "app/Swoft.php"
        ]
    },
...

Composer supportAutomatic loading mode of various modes, there are some historical reasons, because need to be compatible with someObsoleteThe code of. Now more commonly used 2 ways:

  • psr-4: PSR4 standard, preferred method
  • files: load files directly, usually for loadingHelp function, similar to PHP’srequireSyntax to code reuse

requireIdentifies the package that needs to be relied on in the formatPackage Name-Version LimitKey value pair for:

...
    "require": {
        "php": ">=7.0",
        "swoft/framework": "^1.0",
        "swoft/rpc": "^1.0",
        "swoft/rpc-server": "^1.0",
        "swoft/rpc-client": "^1.0",
        "swoft/http-server": "^1.0",
        "swoft/http-client": "^1.0",
        "swoft/task": "^1.0",
        "swoft/http-message": "^1.0",
        "swoft/view": "^1.0",
        "swoft/db": "^1.0",
        "swoft/cache": "^1.0",
        "swoft/redis": "^1.0",
        "swoft/console": "^1.0",
        "swoft/devtool": "^1.0",
        "swoft/session": "^1.0",
        "swoft/i18n": "^1.0",
        "swoft/process": "^1.0",
        "swoft/memory": "^1.0",
        "swoft/service-governance": "^1.0"
    },
...

Aboutversion controlKnowledge of, and>= ^ ~Special characters such as,alpha beta dev dev-masterSuch as logo, just some conventional definition, understand clearly.

require-devIdentifies the packages that the development environment needs to rely on, i.e. packages that the formal environment does not need to use, such as unit tests, etc.;

...
    "require-dev": {
        "eaglewu/swoole-ide-helper": "dev-master",
        "phpunit/phpunit": "^5.7"
    },
...

Similarly, there areautoload-devA that indicates that automatic loading is used in the test environment.

Modular Scheme: Scheme Used by laravel and symfony

ReferencesJson configuration file in symfonyAndJson configuration file in laravel, you will find there is a configuration item:replace.

replaceThis configuration item is difficult to see in ordinary projects, but it is an important configuration in component transformation. Its definition is as follows:

Use the existing package in the project to replace the package that needs to be relied on.

such asJson configuration file in symfony:

...
    "replace": {
        "symfony/asset": "self.version",
        "symfony/browser-kit": "self.version",
        "symfony/cache": "self.version",
        "symfony/config": "self.version",
        "symfony/console": "self.version",
        "symfony/css-selector": "self.version",
        "symfony/dependency-injection": "self.version",
        ...

among them"symfony/asset"Bags, with a separate github warehousesymfony/asset,Symfony projectIt also includes"symfony/asset"Package, usereplaceSymfony can use its own package instead of getting it separately.

The benefits of this:

  • The main package contains all sub-packages, which are used when usingreplaceConfiguration, all modifications and submissions are made in the main package.
  • Other projects can still be usedrequire, using sub-packages alone; Subpackages only accept codes distributed from the main package, and do not accept changes on the subpacket.

Component implementation of Swoft framework

Swoft Dependency in 1.0-beta Version,Swoft project:

...
    "require": {
        "php": ">=7.0",
        "swoft/framework": "^1.0",
        "swoft/rpc": "^1.0",
        "swoft/rpc-server": "^1.0",
        "swoft/rpc-client": "^1.0",
        "swoft/http-server": "^1.0",
        "swoft/http-client": "^1.0",
        "swoft/task": "^1.0",
        "swoft/http-message": "^1.0",
        "swoft/view": "^1.0",
        "swoft/db": "^1.0",
        "swoft/cache": "^1.0",
        "swoft/redis": "^1.0",
        "swoft/console": "^1.0",
        "swoft/devtool": "^1.0",
        "swoft/session": "^1.0",
        "swoft/i18n": "^1.0",
        "swoft/process": "^1.0",
        "swoft/memory": "^1.0",
        "swoft/service-governance": "^1.0"
    },
...

After the renovation,Swoft project, the main project only rely on"swoft/framework":

...
    "require": {
        "php": ">=7.0",
        "swoft/framework": "^1.0"
    },
...

“swoft/framework” project, which contains other sub-packages:

...
    "replace": {
        "swoft/rpc": "self.version",
        "swoft/rpc-server": "self.version",
        "swoft/rpc-client": "self.version",
        "swoft/http-server": "self.version",
        "swoft/http-client": "self.version",
        "swoft/task": "self.version",
        "swoft/http-message": "self.version",
        "swoft/view": "self.version",
        "swoft/db": "self.version",
        "swoft/cache": "self.version",
        "swoft/redis": "self.version",
        "swoft/console": "self.version",
        "swoft/devtool": "self.version",
        "swoft/session": "self.version",
        "swoft/i18n": "self.version",
        "swoft/process": "self.version",
        "swoft/memory": "self.version",
        "swoft/service-governance": "self.version"
    }
...

In which subprojects are declared to submit modifications to the main project:

The whole development process is as follows:

  • InDaydaygo/swoft-framework projectNew component2 Branch Developed This Component Transformation
  • Modify the composer.json file of the Swoft project to quickly obtain the master branch codes of all Swoft components:
    "require": {
        "php": ">=7.0",
        "swoft/framework": "dev-master",
        "swoft/rpc": "dev-master",
        "swoft/rpc-server": "dev-master",
        "swoft/rpc-client": "dev-master",
        "swoft/http-server": "dev-master",
        "swoft/http-client": "dev-master",
        "swoft/task": "dev-master",
        "swoft/http-message": "dev-master",
        "swoft/view": "dev-master",
        "swoft/db": "dev-master",
        "swoft/cache": "dev-master",
        "swoft/redis": "dev-master",
        "swoft/console": "dev-master",
        "swoft/devtool": "dev-master",
        "swoft/session": "dev-master",
        "swoft/i18n": "dev-master",
        "swoft/process": "dev-master",
        "swoft/memory": "dev-master",
        "swoft/service-governance": "dev-master"
    },
  • Copy the code of each component into the swoft-framework project and modify it.composer.jsonOfautoload / replaceConfiguration (click on the link to view specific modifications)

Swoft Component Dependency Diagram:http://naotu.baidu.com/file/7 …

  • Submit swoft-framework code.

Below to pushswoft-viewComponent into the corresponding warehouse as an example:

For the reason of github network speed, gitee is used to speed up the testing process.

Push subprojects to the corresponding github warehouse, refer to:

# 建立 gitee.com:daydaygo/swoft-framework 仓库
git remote add gitee git@gitee.com:daydaygo/swoft-framework.git
git push gitee component2

# 拆分
git subsplit init git@gitee.com:daydaygo/swoft-framework.git
# 更多项目, 一次填写即可
git subsplit publish --heads="component2" --no-tags view:git@gitee.com:daydaygo/swoft-view.git
# 清除生成的临时文件
rm .subsplit

This splitting process takes a long time, and the splitting effect is as follows:gitee.com/daydaygo/swoft-view,gitee.com/daydaygo/swoft-framework

Automation can be achieved by adding github webhook, please refer to:dflydev/dflydev-git-subsplit-github-webhook

Finally, test the split code:

  • Modify the composer.json file of the swoft project and use the new version of the swoft-framework project.
...
  // 现在只需要依赖 swoft/framework, 版本号要制定分支, composer 会默认给分支名带上 dev- 前缀
  "require": {
    "php": ">=7.0",
    "swoft/framework": "dev-component2"
  },
....
  "repositories": {
    "packagist": {
      "type": "composer",
      "url": "https://packagist.phpcomposer.com"
    },
    // 制定包的地址, 这里指向我的 giee 仓库地址
    "0": {
      "type": "vcs",
      "url": "https://gitee.com/daydaygo/swoft-framework"
    }
  }
...
# 删除以前的依赖
rm -rf composer.lock vendor
# 更新
composer install --no-dev

At this point, we are done.

Write at the end

The project is divided into components and sub-packages are pushed to different github warehouses.Such requirements may only be met by writing a large framework. But this is also the fun of writing a framework. The basic knowledge of package management in PHP has always been felt.accomplish a task with easeUntil you meet new problems and put forward new challenges, you will find that there is still more space. I hope you can also feel the joy of this technology.