iLwave's profile蓝色天际PhotosBlogLists Tools Help

Blog


    Nebula 开发日记 3

    上次解决完PHP全局变量作用域的问题之后看看代码很不爽,
    于是又把两个配置文件的包含放回到函数里面,
    对 nConfig 稍作修改使之成为一个配置管理器,
    实现的功能有:装载和解析配置文件,支持访问和管理多种配置方式,提供扩展接口。
    因 nConfig 类被载入之后是作用于全局的类,
    所以可以把所有载入的配置信息交由 nConfig 管理,
    所有已经载入的配置信息均保存在类内部,
    其他模块可以通过类提供的一系列接口来访问和修改配置信息,
    这其中存在几个关键点就是外部接口的统一以及各种类型配置信息的访问方式,
    因此参考数据库模块的处理方法,把每种类型的配置信息操纵方式封装到相应的类中,
    而这些类的访问接口都是统一的,类的原型描述如下:

    abstract class nConfig_ {
       
        abstract public function __construct($arrSection); // $arrSection 基本配置描述信息
       
        abstract public function get($strItem = ''); // 获取一条配置信息,如参数为空则返回所有配置信息
       
        abstract public function set($strItem, $mixValue); // 设置一条配置信息,不保存
        
        abstract public function write($strItem, $mixValue); // 将配置信息写入到存储介质上
       
    }

    要说明的是构造函数 __construct 的参数 $arrSection 是一个数组,
    nebula 的配置信息是以 section (节) 的方式来组织的,
    每个 section 都保存在相应的配置文件里,
    nLoader 中有一个 $arrConfig 全局变量数组是包含所有 section 的容器,
    换一种方式来说即每个 section 都是 $arrConfig 数组的成员,
    最初的时候在 nLoader 描述 $arrConfig = array() 为一个空数组,
    在基本配置文件 config.global.php 中为 $arrConfig 添加一个名为 'global' 的数组成员即 section global,
    代码如下:

    $arrConfig['global'] = array(
        'TYPE' => array('php'),
        'sitename' => 'default'
    );

    其中 TYPE 描述了这个 section 信息的格式为 php,
    而 sitename 是一条自定义的配置信息,描述了站点名称为 default ,
    配置管理器 nLoader 读取 config.global.php 之后根据 TYPE 信息格式选择一个可以操纵这个格式的类 nConfig_php,
    之后生成一个 nConfig_php 的实例,将 $arrConfig['global'] 作为参数传给构造函数完成初始化,
    最后将这个类实例放入自身的资源池中,外部模块可以通过以下接口来访问 global 的配置信息:

        nConfig::sectionExists($strSection) - 判断该配置节是否存在;
        nConfig::get($strSection, $strItem = '') - 从配置节中提取 $strItem 配置项,如后者为空则提取所有;
        nConfig::set($strSection, $strItem, $strValue) - 设置 $strSection 配置节的 $strItem 配置项;
        nConfig::write($strSection, $strItem, $strValue) - 将配置信息写入到存储介质上;

    框架自带了 php 格式的配置信息操纵类 nConfig_php,代码如下:

    class nConfig_php extends nConfig_ {

        private $arrSection = array();

        public function __construct($arrSection) {
            $this->arrSection = $arrSection;
        }

        public function get($strItem = '') {
            return $strItem ? $this->arrSection[$strItem] : $this->arrSection;
        }

        public function set($strItem, $mixValue) {
            //  ...
        }

        public function write($strItem, $mixValue) {
            // ...
        }

    };

    这里在类构造的时候仅是简单地将配置节复制到自身私有数组里,
    而其他类型的配置信息操纵类则需要实现进一步的操作,
    在此暂不实现。

    nLoader 在装载完系统文件之后会自动调用 nConfig 包含 global 和 module 两个配置节,
    之后引导 nContext 正式进入到系统的运行阶段。

    还是冒号减号右括号

     这张...太合适了哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈!

    Nebula 开发日记 2

    昨天写了框架装载器 nLoader,
    在晚上调试的时候遇到问题即函数内部 global 外部全局变量的时候无法取到值,
    而用 isset 函数检测发现全局变量是存在的,
    到网上查了一下 PHP5 的 crash on global 也没有提到类似的现象,
    我曾一度以为是运行时问题(调试环境是作为 ISAPI 模块运行的PHP),
    后来切到 Mac 下用 Apache 调试然而问题依旧,
    难道问题出在基础语法结构上...

    回顾一下,nLoader 的代码是这样的:

    class nLoader {

        private static function validateEnvironment() // 验证框架运行环境
        {
            $boolValid = 0;

            $boolValid = $boolValid || !(phpversion() - 5 > 0); // php version should > 5.0
    //      $boolValid = $boolValid || !(0); // the other env. validation add in the future.
            $boolValid && exit('please check your server environment.'); // 以上任意一项验证不通过即会报错退出
        }
       
        private static function loadSystem() // 载入系统核心文件
        {
            require_once('system/config/config.global.php'); // 载入全局配置文件
            require_once('system/config/config.module.php'); // 载入模块配置文件
            
            require_once('system/core/core.module.php'); // 载入模块控制器
            require_once('system/core/core.context.php'); // 载入模块运行子系统
        }
       
        public static function initialize() // 引导器初始化接口
        {
            self::validateEnvironment();
            self::loadSystem();
            nContext::initialize(); // 系统文件载入完成之后启动上下文对象(模块运行子系统)
        }

    };

    框架运行环境检测通过之后会载入必须的配置文件和系统运行文件,
    系统首先初始化模块运行子系统,在 nContext::initialize() 会调用模块控制器 nModuleHandler 中的 loadModule 函数,
    而 nModuleHandler::loadModule() 需要访问 config.module.php 中定义的模块配置参数 $arrConfig['modules'] ,
    问题就出在这里,loadModule 函数能够探测到 $arrConfig['modules'] 是已定义的,
    但是将之 global 之后试图访问的时候却无法取到值,很奇怪。

    想了很长时间也不知道怎么回事,于是先上床睡觉~

    最近喜欢上了一个叫 Solitaire 的 n-gage 游戏,
    里面包含了 12 种纸牌玩法,
    windows 里的蜘蛛纸牌和纸牌游戏也能在里面玩到,
    这东西拿来睡前消遣真是非常不错...下面是截图,
    游戏的开始画面和本人比较喜欢的 Yukon 游戏画面 {
     
    } 貌似昨晚因为郁闷所以玩到两点多...

    今早起床的时候继续想问题,把 PHP 包含文件的四种方法都回顾一番,
    忽然记起很久以前看资料的时候偶然瞥到的一句话,
    PHP 的 include 无非是把文件读进来然后把 <? 和 ?> 之间的代码 eval 一下,
    至于几种包含方式有啥区别则不重要,底层实现是一致的,
    那么我在函数外部访问全局变量正常,
    访问定义在顶层文件(index.php)的全局变量也正常,
    而访问定义在被包含文件中的全局变量出现问题,
    会不会是代码被 eval 之后没有加入到全局域中去?

    于是进一步测试,在 nLoader::loadSystem() 里面载入文件之后访问 $arrConfig - 正常,
    在 nContext::initialize() 里访问就取不到值了,
    而被 nContext::initialize() 调用的 nModuleHandler::loadModule() 显然更加别提~
    于是自然而然就想到了变量作用域的问题,被 nLoader::loadSystem() 包含进来的几个配置文件,
    被 eval 之后自然也成为 loadSystem() 的内部私有变量了,
    所以这个函数执行完之后那些“全局变量”也就随函数一起被资源回收了,
    至于其他函数想访问这些变量,则只能见其踪而不见其影...

    继续研究,在 PHP 里的全局变量不能在函数内部定义(包括通过函数进行文件包含),
    而 PHP 中的函数或者类无论在哪里定义,都是处于全局作用域的,
    也就是说框架中的外部模块可以通过函数动态载入进来。

    既然问题找到,解决起来也就容易,
    把定义全局变量的配置文件包含到函数外面就可以了,
    于是 nLoader 写成这样:

    require_once('system/config/config.global.php'); // 载入全局配置文件
    require_once('system/config/config.module.php'); // 载入模块配置文件

    class nLoader {

        private static function validateEnvironment() // 验证框架运行环境
        {
            $boolValid = 0;

            $boolValid = $boolValid || !(phpversion() - 5 > 0); // php version should > 5.0
    //      $boolValid = $boolValid || !(0); // the other env. validation add in the future.
            $boolValid && exit('please check your server environment.'); // 以上任意一项验证不通过即会报错退出
        }
       
        private static function loadSystem() // 载入系统核心文件
        {
            require_once('system/core/core.module.php'); // 载入模块控制器
            require_once('system/core/core.context.php'); // 载入模块运行子系统
        }
       
        public static function initialize() // 引导器初始化接口
        {
            self::validateEnvironment();
            self::loadSystem();
            nContext::initialize(); // 系统文件载入完成之后启动上下文对象(模块运行子系统)
        }

    };

    运行之后成功访问到全局变量 $arrConfig['modules'],问题解决。

    Nebula 开发日记 1

    性质:Web应用程序开发框架;
    环境:PHP 5.0或更高版本,MySQL 5.0或更高版本;

    Nebula (v1.5) 是基于 PHP 面向对象特性实现的,
    整个框架由唯一的用户访问入口 index.php 处理所有请求,
    按需调用相关的模块完成一项或多项功能。
    Nebula 由系统核心、系统支持模块和外围(第三方)模块组成,
    所有模块遵循面向对象的编程理念并且引入MVC设计模式,
    不仅规范了编程接口也使得框架极强的定制和可扩展性。

    下面是设计草图:



    初步设定的运行过程如下:

    用户访问 http://demo.site/?m=example&a=view 产生一个业务请求,
    此时由默认入口 index.php 接受该请求并初始化系统,
    之后分析 m=example 得到所需的业务类型 example,
    系统检查业务映射表调用相应模块进行处理,
    再把数据送入内容渲染器进行格式化后输出。

    (待续)

    庄子说话不说话

    来这里写点东西的时间,其实是有的。

    都说坚持写日记是个好习惯,
    貌似我连写个周记的想法都不见得有,
    倒不是说懒不懒的问题,
    我虽然是个十足的懒人却也偶尔会专注做点事情,
    主要原因归根结底还是,
    没啥事情好写的...

    我就纳闷一些文学小青年怎么能三天两头码出成百上千个字来,
    现在这种日记写给人家看的时代,毕竟是和以前大大的不同了。

    我也不想写些毫无意义的事情,
    那些关于过日子的流水帐或者人生的感慨还是扔到角落里去,
    这个blog的访问统计表明大部分点击都是来自搜索引擎,
    并且九成以上都是涉及到技术的,
    很高兴这个blog能为一部分人解决问题提供帮助,
    这也是蓝色天际存在的最大意义。

    接下来几天要再次重写Nebula系统,
    使之可以结合Drupal共同构成一个门户网站,
    前者负责内容表达而后者负责内容管理,
    之所以采用Drupal是因为其强大的内容管理功能以及可扩展机制,
    而其缺点也显而易见即不适合构建国内的门户网站,
    Drupal每次页面访问都会产生数十个数据库查询,
    这对于国内这种信息爆炸式的门户网站而言显然是无法容忍的,
    于是新一代的Nebula便应运而生,
    采用全新的架构,引入三级缓存机制,
    从运行时、数据库到静态页面逐层缓存达到降低数据库查询的目的,
    从根本上降低服务器负荷提高并发请求的处理能力,
    参考操作系统的架构引入“微内核”的概念,
    为整个系统的开发提供最大的自由度...

    Nebula开发日记将于明日起连载,敬请期待~