配置系统的思考

配置系统在整个软件的生命周期里,有着很重要的角色。例如:

在新公司上班,第一天需要配置开发环境。。。

多环境部署,开发、测试、预发布、生产不同环境的配置。。。

项目的数据库,缓存,负载均衡,Nginx各种服务的配置。。。

做这么多年的开发,说来好笑,一直在跟配置系统打交道,但却没有花时间思考配置系统存在的意义。那么如何在目前Linux+Nginx+MySQL+PHP的构架下,尝试合适自己的配置系统呢?

常见的配置系统

既然不知道什么样的配置系统适合自己,那么我们可以看看别人家,是如何使用配置系统的。

Phalcon

Phalcon框架是我使用时间较长的开发框架,先看看它内部的配置如何实现。

<?php

use Phalcon\Config;

$config = new Config(
    [
        'test' => [
            'parent' => [
                'property'  => 1,
                'property2' => 'yeah',
            ],
        ],
    ]
);

echo $config->get('test')->get('parent')->get('property');  // displays 1
echo $config->test->parent->property;                       // displays 1
echo $config->path('test.parent.property');                 // displays 1

#甚至你可以注入配置到di
use Phalcon\Di\FactoryDefault;
use Phalcon\Config;

// Create a DI
$di = new FactoryDefault();

$di->set(
    'config',
    function () {
        $configData = require 'config/config.php';

        return new Config($configData);
    }
);

实现的原理是根据传入的数组转换Phlacon\Config对象的属性。支持不同类型配置器,例如ini、Json、Php、yaml等,你可以理解为Phlacon\Config是一个工厂模式,生产不同的类型的配置实例。

Magento

这是一个流行的开源电子商务框架。在1.x的框架版本都是采用xml去实现的。那时候发现xml做配置,非常“灵活”。注意,我这里用一个非常的形容词,这意味调试开发成本会比较高。那时候我的时间大部分都花费在xml文件里查找对应的配置。幸好,官方终于在2.x版本优化过来了,终于可以解脱了。

The Magento 2 deployment configuration replaces local.xml in Magento 1.x.

config.php 代码实例:

return array (
  'modules' =>
  array (
    'Magento_Core' => 1,
    'Magento_Store' => 1,
    'Magento_Theme' => 1,
    'Magento_Authorization' => 1,
    'Magento_Directory' => 1,
    'Magento_Backend' => 1,
    'Magento_Backup' => 1,
    'Magento_Eav' => 1,
    'Magento_Customer' => 1,
...
  ),
);

json

JSON文件格式是一个伟大的发明。简单的key和value的形式,就解决大部分配置文件,主要应用在不需要复杂逻辑配置,比如Composer、NPM等。

# composer.json
{
    "config": {
        "preferred-install": {
            "my-organization/stable-package": "dist",
            "my-organization/*": "source",
            "partner-organization/*": "auto",
            "*": "dist"
        }
    }
}
# package.josn

{ "name": "ethopia-waza",
  "description": "a delightfully fruity coffee varietal",
  "version": "1.2.3",
  "devDependencies": {
    "coffee-script": "~1.6.3"
  },
  "scripts": {
    "prepare": "coffee -o lib/ -c src/waza.coffee"
  },
  "main": "lib/waza.js"
}

YAML

在GitLab中CI构建配置文件是采用YML。原因是在构建的过程需要存储复杂业务流程,整体逻辑较多,YML适合应用于这类场景。

# see https://gitlab.com/help/ci/yaml/README.md#jobs
# Select image
image: geekwho/code:php
stages:
  - phplint
  - phpfixer
  - build
  - test
  - deploy

# php lint
phplint:
  stage: phplint
  script:
  - bash bin/phplint.sh
  only:
  - master
  - prelease
  - dev

# php code style
phpfixer:
  stage: phpfixer
  script:
  - bash bin/phpfixer.sh
  only:
  - master
  - prelease
  - dev

# unit test
test:
  stage: test
  script:
  - bash bin/test.sh
  only:
  - master
  - prelease
  - dev
  allow_failure: true

PHP数组

最简单的配置系统可以直接采用PHP自带的数组。数组的实现本身也是hash table 。

<?php
// 直接返回数组元素
return [
    'database' => [
      'adapter'     => 'Mysql',
      'host'        => 'localhost',
      'username'    => 'root',
      'password'    => '',
      'dbname'      => '@@name@@',
      'charset'     => 'utf8',
    ],
    'version' => '1.0',

    /**
     * if true, then we print a new line at the end of each execution
     *
     * If we dont print a new line,
     * then the next command prompt will be placed directly on the left of the output
     * and it is less readable.
     *
     * You can disable this behaviour if the output of your application needs to don't have a new line at end
     */
    'printNewLine' => true,
];
// 可以在配置里做一些逻辑判断
<?php

$dsn = 'mysql:host=localhost;dbname=yii2basic';
return [
    'class' => 'yii\db\Connection',
    'dsn' => $dsn,
    'username' => 'root',
    'password' => '',
    'charset' => 'utf8',
];
// 甚至还可以使用静态变量
<?php

class Config {
    public static $db = 'mysql';
    public static $user = 'root';
    public static $passwd = '';
    public static $host = 'locahost';

}

Bash

甚至有时候在Bash环境也需要添加部分文件,我是这样做的。

# @Author: geekwho
# @Date:   2018-09-18 11:11:11
# @Last Modified by:   geekwho
# @Last Modified time: 2018-09-17 11:11:11
# 配置文件
project="wiki"

domain=".xbc.me"

user="geekwho"

host="your host"

port="your port"

dest=""

# 然后在你需要使用变量的地方进行加载
source ./.config.sh

环境变量

很多时候我们需要判断的环境变量,比如dev、stg、pre、pro等不同环境。

项目目录

这类方式就是直接在当前项目下建一个隐藏文件,类似 .env.dev 代表当前的环境。不好的地方,因为在当前项目下,容易被误修改或删除,导致环境判断异常。

php.ini

直接在php.ini添加自定义的环境变量,例如env=dev。那么在bash环境下,还需要单独去做一次环境变量的解析。

/etc

直接在系统文件下建立一个环境变量的文件。例如/etc/.env.dev。这类操作需要运维配置设置对应环境的变量文件。

两者结合

如何把环境变量和配置系统结合起来呢?

根据环境变量独立配置文件

推荐的配置目录结构如下:

app
    config
        dev
            config.php
        test
            config.php
        pre
            config.php
        prd
            config.php
// 实例
<?php

class Config {
    public static $db = 'mysql';
    public static $user = 'root';
    public static $passwd = '';
    public static $host = 'locahost';

}

All in ONE

全部环境变量全部都写同一个文件里。

#app/config/db.php
<?php

class Config {
    public static $db = [
      'dev' => 'mysql',
      'test' => 'mysql',
      'pre' => 'mysql',
      'prd' => 'mysql',
    ];
    public static $user_dev = [
      'dev' => 'root',
      'test' => 'root',
      'pre' => 'root',
      'prd' => 'root',
    ];
    public static $passwd = [
      'dev' => '',
      'test' => '',
      'pre' => '',
      'prd' => '',
    ]
    public static $hos = [
      'dev' => 'localhost',
      'test' => 'localhost',
      'pre' => 'localhost',
      'prd' => 'localhost',
    ]

}

参考链接

  1. phalcon config
  2. magento config
  3. composer config
  4. npm config
  5. GitLabv CI YAML
  6. PHP Array
  7. LaraDock

发表评论

电子邮件地址不会被公开。 必填项已用*标注