求推荐手机,目前只看中一部华为手机推荐性价比高nova,预算1000-1500左右

你可能感兴趣的文章
1 任何一个程序一旦发布就意味着它已经过时了。 2 让需求根据程序调整往往要比让程序...
如何改变Apache端口:找到Apache安装目录下conf目录下的httpd.conf文件。打开它,找到...
虽然通常在PHP中进行大量数组运算从一定程度上反应程序设计上可能存在问题,但是粗略...
什么是PHP PHP代表了超文本处理器,这意味着你必须知道,它是一种服务器端的处理语言...
PHP中session详解 综述 Session指的就是用户在浏览某个网站时,从进入网站到浏览器关...debug+trace模式可以查看开发过程中TP的错误信息,可以更好地帮助开发者debug。但是debug模式的开启还不是简单的在配置文件中中设置就可以的,经过查资料摸索,找到一种有效的方法。
首先在你已经部署好了ThinkPHP的项目目录
然后注意是在入口文件开启调试模式,在入口文件index.php 中写入一下代码define(&APP_DEBUG&,true); 首先删除Runtime目录 ,然后再次运行一下,你会发现runtime目录下面的~runtime.php 文件没有了,说明你的调试模式开启成功了
之所以这个~runtime.php文件删除 ,这个文件是编译后的文件 会有缓存,所以在调试模式期间我们不用担心因为缓存而造成其他错误
trace页面的&也是我们开发者获取错误信息的而一个途径,所以我们需要开启trace页面,在THinkPHp3.0版本中trace页面是默认没有开启的,需要我们手动 的在项目配置文件中添加
&SHOW_PAGE_TRACE&&&&&&&& =&true,&& //&显示页面Trace信息
想要看看trace信息是否开启了,只要我们在 IndexAction.class.php 中的index方
法中加上$this-&display();
然后再次运行如果你看到了如下界面,说明你的调试模式,以及trace 以及开启了
阅读(...) 评论()利用xdebug和netbeans调试thinkphp源码及流程分析
发布时间: 18:08:11
这周活比较轻松,正好过一遍thinkphp源码(3.1.2版),弄清楚该框架内部实现的流程,增长些知识。
第一步,安装xdebug,写个测试页,里面写上phpinfo();把内容复制贴到页面里,点击提交,之后会提示本机php对应的xdebug版本,下载后放到php目录下的ext目录内,再把下面的配置写入php.ini内,之后重启服务器,再刷新测试页面,看界面上是否有xdebug字样。
zend_extension=&D:\server\php\php-5.3.8-Win32-VC9-x86\ext\php_xdebug-2.1.4-5.3-vc9.dll&
[Xdebug]是否开启自动跟踪 xdebug.auto_trace = O是否开启异常跟踪 xdebug.show_exception_trace = O是否开启远程调试自动启动 xdebug.remote_autostart = O是否开启远程调试 xdebug.remote_enable = O允许调试的客户端IP远程调试的端口(默认9000) xdebug.remote_port=9001 ;调试插件dbgp xdebug.remote_handler=是否收集变量 xdebug.collect_vars = O是否收集返回值 xdebug.collect_return = O是否收集参数 xdebug.collect_params = O跟踪输出路径 xdebug.trace_output_dir=&c:\xdebug& ;是否开启调试内容 xdebug.profiler_enable=O调试输出路径 xdebug.profiler_output_dir=&c:\xdebug& xdebug.remote_host=localhost
第二步,打开netbeans,在工具-选项-php-调试框内,把调试器端口写成和php.ini内xdebug.remote_port一致,点击应用-确定。
第三步,新建项目,也就是把thinkphp创建的项目导入进去,进入项目内,点击调试项目,之后会弹出一个会话框,在项目URL和索引文件填入正确的信息,之后便可以调试了。
第四步,开始调试。进入项目的一个具体页面,点击调试文件或是调试项目,之后调试便开始了,按F7键进行调试。下面,我便把调试后的的心得写下来。
1)&由于thinkphp是单入口的文件,因此调试界面首先便跳到index.php中,该页面主要负责定义项目名称、项目路径、thinkphp所在路径、是否开启调试模式,之后便引入ThinkPHP.php。
2)在ThinkPHP.php页面里,主要是定义了项目开始运行时间、开始时的内存使用情况、重新检测了是否定义项目路径、缓存目录路径、项目是否开始调试模式、~runtime.php存放地址,若是项目开启调试,则进入THINK_PATH.'Common/runtime.php',没有开启则直接进入已编译好的~runtime.php.,这里属于调试模式,即APP_DEBUG为TRUE。
3)runtime.php文件主要负责检测是否定义thinkphp路径,没有的话就退出,这应该是阻止恶意链接吧,定义版本信息,检测php的版本,定义系统常量、URL的4种模式、目录常量(tp系统的和项目的),加载运行所需文件,记录加载文件文件时间,执行Think::Start()。这里着重解释下load_runtime_file()函数。
// 加载运行时所需要的文件 并负责自动目录生成 function load_runtime_file() {
// 加载系统基础函数库
// require_cache函数所在文件,要先引入,才能正确执行
require THINK_PATH.'Common/common.php';
// 读取核心文件列表
// 因为接下来便是进入Think.class.php文件,因此要引入该文件
// 同时由于在执行过程中可能会遇到错误或是异常,便引入ThinkException.class.php异常处理类
// 在App::run()方法内会执行tag函数,会用Behavior.class.php类,于是也被一同引入
$list = array(
CORE_PATH.'Core/Think.class.php',
CORE_PATH.'Core/ThinkException.class.php',
// 异常处理类
CORE_PATH.'Core/Behavior.class.php',
// 加载模式文件列表
foreach ($list as $key=&$file){
// require_cache 可以看成是一个优化的require方法
// 实际上是引入了static静态变量,避免文件重复引入
// 在thinkphp中static的思维贯穿其中
if(is_file($file))
require_cache($file);
// 加载系统类库别名定义
//alias_import(include THINK_PATH.'Conf/alias.php');
// 检查项目目录结构 如果不存在则自动创建
if(!is_dir(LIB_PATH)) {
// 创建项目目录结构
build_app_dir();
}elseif(!is_dir(CACHE_PATH)){
// 检查缓存目录
check_runtime();
}elseif(APP_DEBUG){
// 调试模式切换删除编译缓存
if(is_file(RUNTIME_FILE))
unlink(RUNTIME_FILE);
4)进入Thinkphp,执行静态方法Start(),该方法重新定义了异常、错误、自动加载机制,执行Think::buildApp()方法
a)Think::buildApp()方法主要实现了thinkphp官方手册中的“惯例配置-&项目配置-&调试配置-&分组配置-&扩展配置-&动态配置”说明。
// 加载底层惯例配置文件 C(include THINK_PATH.'Conf/convention.php'); C(include THINK_PATH.'Conf/config.php');
// 加载项目配置文件 C(include CONF_PATH.'config.php');
// 加载框架底层语言包 L(include THINK_PATH.'Lang/'.strtolower(C('DEFAULT_LANG')).'.php');
// 默认加载系统行为扩展定义 C('extends', include THINK_PATH.'Conf/tags.php');
// 默认加载项目配置目录的tags文件定义 C('tags', include CONF_PATH.'tags.php');
THINK_PATH.'Common/functions.php', // 标准模式函数库 CORE_PATH.'Core/Log.class.php',
// 日志处理类 CORE_PATH.'Core/Dispatcher.class.php', // URL调度类 CORE_PATH.'Core/App.class.php',
// 应用程序类 CORE_PATH.'Core/Action.class.php', // 控制器类 CORE_PATH.'Core/View.class.php',
// 加载项目公共文件 include COMMON_PATH.'common.php';
// 加载系统别名文件,这里主要在tag函数中利用到 include THINK_PATH.'Conf/alias.php';
// 加载项目别名文件,如果有的话,若是项目中配置了,可以在项目中的Behavior目录里写相关的行为代码 include CONF_PATH.'alias.php';
// 调试模式加载系统默认的配置文件 C(include THINK_PATH.'Conf/debug.php');
// 加载对应的项目配置文件
C( include CONF_PATH . C('APP_STATUS') . '.php');
5)上述方法执行完后,进入App.class.php中执行App::run()方法。
a)tag('app_init'),项目初始化标签,在tag.php文件中可以看到,app_init对应的值为空,因此这个标签是什么也没执行。之后在第九条详细解释tag方法。
6)执行App::init()方法,该方法首先设置时区,默认为PRC,可以通过在项目中配置DEFAULT_TIMEZONE的值来修改,之后加载动态项目公共文件和配置
a)load_ext_file()方法主要是加载动态扩展文件
* 加载动态扩展文件
* @return void
*/ function load_ext_file() {
// 通过在项目里配置LOAD_EXT_FILE、LOAD_EXT_CONFIG来动态加载文件
// 加载自定义外部文件
// LOAD_EXT_FILE =& 'guest,user';
// 那么便会加载项目公共目录(Common)内的guest.php和user.php文件
if (C('LOAD_EXT_FILE')) {
$files = explode(',', C('LOAD_EXT_FILE'));
foreach ($files as $file) {
$file = COMMON_PATH . $file . '.php';
if (is_file($file))
// 加载自定义的动态配置文件
// LOAD_EXT_CONFIG =& 'guest,user';
// 那么便会加载项目配置(Conf)目录内的guest.php和user.php文件
if (C('LOAD_EXT_CONFIG')) {
$configs = C('LOAD_EXT_CONFIG');
if (is_string($configs))
$configs = explode(',', $configs);
foreach ($configs as $key =& $config) {
$file = CONF_PATH . $config . '.php';
if (is_file($file)) {
is_numeric($key) ? C(include $file) : C($key, include $file);
// 加载不同的操作系统下的配置
// 以便在不同操作系统执行工具的不同平台的版本
if (C('OS_CONFIG')) {
if (preg_match('/WIN/', PHP_OS)) {
$file = CONF_PATH . 'win.php';
$file = CONF_PATH . '.php';
if (is_file($file))
C(include $file);
7)进入Dispatcher.class.php执行Dispatcher::dispatch()方法。
* URL映射到控制器
* @access public
* @return void
*/ static public function dispatch() {
// 项目的URL_MODEL为2,也就是define('URL_REWRITE',
2)即REWRITE模式
C('URL_MODEL');
// 判断URL里面是否有兼容模式参数
// VAR_PATHINFO的值为s
// 这时$_GET没有接收到参数,而且即使有,参数中也没有s的
if(!empty($_GET[C('VAR_PATHINFO')])) {
$_SERVER['PATH_INFO']
= $_GET[C('VAR_PATHINFO')];
unset($_GET[C('VAR_PATHINFO')]);
// 条件不符
if($urlMode == URL_COMPAT ){
// 兼容模式判断
define('PHP_FILE',_PHP_FILE_.'?'.C('VAR_PATHINFO').'=');
// URL_REWRITE在runtime中的定义为2
// 条件符合,定义PHP_FILE常量
}elseif($urlMode == URL_REWRITE ) {
// 当前项目地址
dirname(_PHP_FILE_);
if($url == '/' || $url == '\\')
'';
define('PHP_FILE',$url);
// 条件不符
//当前项目地址
define('PHP_FILE',_PHP_FILE_);
// 项目没有开启子域名
// 开启子域名部署
if(C('APP_SUB_DOMAIN_DEPLOY')) {
= C('APP_SUB_DOMAIN_RULES');
$subDomain
= strtolower(substr($_SERVER['HTTP_HOST'],0,strpos($_SERVER['HTTP_HOST'],'.')));
define('SUB_DOMAIN',$subDomain); // 二级域名定义
if($subDomain && isset($rules[$subDomain])) {
$rules[$subDomain];
}elseif(isset($rules['*'])){ // 泛域名支持
if('www' != $subDomain && !in_array($subDomain,C('APP_SUB_DOMAIN_DENY'))) {
$rules['*'];
if(!empty($rule)) {
// 子域名部署规则 '子域名'=&array('分组名/[模块名]','var1=a&var2=b');
explode('/',$rule[0]);
array_pop($array);
if(!empty($module)) {
$_GET[C('VAR_MODULE')]
$domainModule
if(!empty($array)) {
$_GET[C('VAR_GROUP')]
array_pop($array);
$domainGroup
if(isset($rule[1])) { // 传入参数
parse_str($rule[1],$parms);
array_merge($_GET,$parms);
// 该变量的值不为空,因此条件不成立
// 分析PATHINFO信息
if(empty($_SERVER['PATH_INFO'])) {
explode(',',C('URL_PATHINFO_FETCH'));
foreach ($types as $type){
if(0===strpos($type,':')) {// 支持函数判断
$_SERVER['PATH_INFO'] =
call_user_func(substr($type,1));
}elseif(!empty($_SERVER[$type])) {
$_SERVER['PATH_INFO'] = (0 === strpos($_SERVER[$type],$_SERVER['SCRIPT_NAME']))?
substr($_SERVER[$type], strlen($_SERVER['SCRIPT_NAME']))
$_SERVER[$type];
// 分割符为/
$depr = C('URL_PATHINFO_DEPR');
if(!empty($_SERVER['PATH_INFO'])) {
// 在tags.php中path_info的值为空,因此这里不执行操作
tag('path_info');
// 拆分PATH_INFO,具体的可以参照手册中pathinfo函数
pathinfo($_SERVER['PATH_INFO']);
// 定义__EXT__常量
define('__EXT__', isset($part['extension'])?strtolower($part['extension']):'');
if(C('URL_HTML_SUFFIX')) {
$_SERVER['PATH_INFO'] = preg_replace('/\.('.trim(C('URL_HTML_SUFFIX'),'.').')$/i', '', $_SERVER['PATH_INFO']);
}elseif(__EXT__) {
$_SERVER['PATH_INFO'] = preg_replace('/.'.__EXT__.'$/i','',$_SERVER['PATH_INFO']);
// 由于项目中没有采用路由规则,因此条件成立
// 检测路由规则 如果没有则按默认规则调度URL
if(!self::routerCheck()){
// 拆分$_SERVER['PATH_INFO']为数组
$paths = explode($depr,trim($_SERVER['PATH_INFO'],'/'));
// VAR_URL_PARAMS值为_URL_
if(C('VAR_URL_PARAMS')) {
// 把$_SERVER['PATH_INFO']的按/分割成数组,并赋值给$_GET的_URL_变量
$_GET[C('VAR_URL_PARAMS')]
// APP_GROUP_LIST为项目中设置的组
// VAR_GROUP置为g,由于$_GET没有接收此参数,因此条件成立
if (C('APP_GROUP_LIST') && !isset($_GET[C('VAR_GROUP')])){
$var[C('VAR_GROUP')] = in_array(strtolower($paths[0]),explode(',',strtolower(C('APP_GROUP_LIST'))))? array_shift($paths) : '';
if(C('APP_GROUP_DENY') && in_array(strtolower($var[C('VAR_GROUP')]),explode(',',strtolower(C('APP_GROUP_DENY'))))) {
// 禁止直接访问分组
// 还没有定义模块名称
if(!isset($_GET[C('VAR_MODULE')])) {
$var[C('VAR_MODULE')]
array_shift($paths);
$var[C('VAR_ACTION')]
array_shift($paths);
// 解析剩余的URL参数
preg_replace('@(\w+)\/([^\/]+)@e', '$var[\'\\1\']=strip_tags(\'\\2\');', implode('/',$paths));
// 把$var和$_GET合并形成新的$_GET数组,这时URL映射基本完整
array_merge($var,$_GET);
define('__INFO__',$_SERVER['PATH_INFO']);
// URL常量
define('__SELF__',strip_tags($_SERVER['REQUEST_URI']));
// 当前项目地址
define('__APP__',strip_tags(PHP_FILE));
// 获取分组 模块和操作名称
if (C('APP_GROUP_LIST')) {
// 默认分组为Home,这里主要依据当前访问的文件的位置
// 如果文件为Home分组下就是Home
define('GROUP_NAME', self::getGroup(C('VAR_GROUP')));
// 分组URL地址
define('__GROUP__',(!empty($domainGroup) || strtolower(GROUP_NAME) == strtolower(C('DEFAULT_GROUP')) )?__APP__ : __APP__.'/'.GROUP_NAME);
// 定义项目基础加载路径
define('BASE_LIB_PATH', (defined('GROUP_NAME') && C('APP_GROUP_MODE')==1) ? APP_PATH.C('APP_GROUP_PATH').'/'.GROUP_NAME.'/' : LIB_PATH);
if(defined('GROUP_NAME')) {
if(1 == C('APP_GROUP_MODE')){ // 独立分组模式
$config_path
BASE_LIB_PATH.'Conf/';
$common_path
BASE_LIB_PATH.'Common/';
}else{ // 普通分组模式
$config_path
CONF_PATH.GROUP_NAME.'/';
$common_path
COMMON_PATH.GROUP_NAME.'/';
// 加载分组配置文件
if(is_file($config_path.'config.php'))
C(include $config_path.'config.php');
// 加载分组函数文件
if(is_file($common_path.'function.php'))
include $common_path.'function.php';
// 定义模块名和方法名常量
define('MODULE_NAME',self::getModule(C('VAR_MODULE')));
define('ACTION_NAME',self::getAction(C('VAR_ACTION')));
// 当前模块和分组地址
$moduleName
defined('MODULE_ALIAS')?MODULE_ALIAS:MODULE_NAME;
if(defined('GROUP_NAME')) {
define('__URL__',!empty($domainModule)?__GROUP__.$depr : __GROUP__.$depr.$moduleName);
define('__URL__',!empty($domainModule)?__APP__.'/' : __APP__.'/'.$moduleName);
$tmpAppUrl = explode('/', __URL__);
//define('__APPURL__', '/' . $tmpAppUrl[1] . '/' . $tmpAppUrl[2]);
define('__APPURL__', './');
// 当前操作地址
define('__ACTION__',__URL__.$depr.(defined('ACTION_ALIAS')?ACTION_ALIAS:ACTION_NAME));
//保证$_REQUEST正常取值
$_REQUEST = array_merge($_POST,$_GET); }
8)回到App::init()方法,定义当前请求的系统常量、URL调度结束、页面压缩输出支持、系统变量安全过滤(过滤$_GET、$_POST)、设置模板相关信息、动态配置异常界面(若是觉得tp异常界面不友好的话,可以重新设计下界面,并在放在项目目录内,在配置文件内通过TMPL_EXCEPTION_FILE来设定)
9)回到App::run()方法,执行tag('app_begin')方法,这里详细介绍下tag方法执行机制
* 处理标签扩展
* @param string $tag 标签名称
* @param mixed $params 传入参数
* @return mixed
*/ function tag($tag, &$params=NULL) {
// 这里$tag的值为app_begin
// 因为在Think.class.php文件中的静态方法buildapp()中已经将tags.php中
// 关于行为的值赋值给extends键,通过查看文件可知这里的app_begin是有值的
// 值为ReadHtmlCache
// 系统标签扩展
= C('extends.' . $tag);
// 应用标签扩展
= C('tags.' . $tag);
// $tags这里没有值,条件不成立
if (!empty($tags)) {
// 合并扩展
if(empty($tags['_overlay']) && !empty($extends)) {
$tags = array_unique(array_merge($extends,$tags));
// 通过设置 '_overlay'=&1 覆盖系统标签
} elseif (isset($tags['_overlay'])){
unset($tags['_overlay']);
// 把extends的值赋给$tags
} elseif (!empty($extends)) {
if($tags) {
if(APP_DEBUG) {
G($tag.'Start');
trace('[ '.$tag.' ] --START--','','INFO');
// 执行扩展
foreach ($tags as $key=&$name) {
// 指定行为类的完整路径 用于模式扩展
if(!is_int($key)) {
// 执行B方法
B($name, $params);
// 记录行为的执行日志
if(APP_DEBUG) {
trace('[ '.$tag.' ] --END-- [ RunTime:'.G($tag.'Start',$tag.'End',6).'s ]','','INFO');
// 未执行任何行为 返回false
* 执行某个行为
* @param string $name 行为名称
* @param Mixed $params 传人的参数
* @return void
*/ function B($name, &$params=NULL) {
// 把ReadHtmlCache的值传过来,并重新组合为ReadHtmlCacheBehavior
= $name.'Behavior';
if(APP_DEBUG) {
G('behaviorStart');
// 执行ReadHtmlCacheBehavior类,这里就用到了前面的thinkphp自定义的autoload方法
// 因为ReadHtmlCacheBehavior.class.php没有加载进来,因此在new之前要加载进来
// 加载后执行实例化操作,由于ReadHtmlCacheBehavior都是继承Behavior类,因此在实例化时
// 也自动执行了析构函数__construct,该函数类似C方法
= new $class();
// 执行ReadHtmlCacheBehavior类的run方法,因为没有设定HTML_CACHE_RULES,因此下面是不执行操作的
$behavior-&run($params);
if(APP_DEBUG) { // 记录行为的执行日志
G('behaviorEnd');
trace('Run '.$name.' Behavior [ RunTime:'.G('behaviorStart','behaviorEnd',6).'s ]','','INFO');
* 系统自动加载ThinkPHP类库
* 并且支持配置自动加载路径
* @param string $class 对象类名
* @return void
*/ public static function autoload($class) {
// 检查是否存在别名定义
if(alias_import($class))
defined('BASE_LIB_PATH')?BASE_LIB_PATH:LIB_PATH;
defined('GROUP_NAME') && C('APP_GROUP_MODE')==0 ?GROUP_NAME.'/':'';
// 这里的$file变成了ReadHtmlCacheBehavior.class.php
$class.'.class.php';
// 加载行为,此条件成立,这里加载多个行为,系统核心的、系统扩展的、项目自身的(后面两个时一样的)
// 加载完后变返回
if(substr($class,-8)=='Behavior') {
if(require_array(array(
CORE_PATH.'Behavior/'.$file,
EXTEND_PATH.'Behavior/'.$file,
LIB_PATH.'Behavior/'.$file,
$libPath.'Behavior/'.$file),true)
|| (defined('MODE_NAME') && require_cache(MODE_PATH.ucwords(MODE_NAME).'/Behavior/'.$file))) {
}elseif(substr($class,-5)=='Model'){ // 加载模型
if(require_array(array(
LIB_PATH.'Model/'.$group.$file,
$libPath.'Model/'.$file,
EXTEND_PATH.'Model/'.$file),true)) {
}elseif(substr($class,-6)=='Action'){ // 加载控制器
if(require_array(array(
LIB_PATH.'Action/'.$group.$file,
$libPath.'Action/'.$file,
EXTEND_PATH.'Action/'.$file),true)) {
}elseif(substr($class,0,5)=='Cache'){ // 加载缓存驱动
if(require_array(array(
EXTEND_PATH.'Driver/Cache/'.$file,
CORE_PATH.'Driver/Cache/'.$file),true)){
}elseif(substr($class,0,2)=='Db'){ // 加载数据库驱动
if(require_array(array(
EXTEND_PATH.'Driver/Db/'.$file,
CORE_PATH.'Driver/Db/'.$file),true)){
}elseif(substr($class,0,8)=='Template'){ // 加载模板引擎驱动
if(require_array(array(
EXTEND_PATH.'Driver/Template/'.$file,
CORE_PATH.'Driver/Template/'.$file),true)){
}elseif(substr($class,0,6)=='TagLib'){ // 加载标签库驱动
if(require_array(array(
EXTEND_PATH.'Driver/TagLib/'.$file,
CORE_PATH.'Driver/TagLib/'.$file),true)) {
// 根据自动加载路径设置进行尝试搜索
explode(',',C('APP_AUTOLOAD_PATH'));
foreach ($paths as $path){
if(import($path.'.'.$class))
// 如果加载类成功则返回
接着执行Session初始化操作,记录应用初始化时间
10)前面的准备工作都做完后,接下来便进入执行应用程序App::exec()方法了,到这一步时,基本就是水到渠成的了,利用前面获取的模块和方法通过检测方法是否存在,并通过ReflectionMethod类来获悉当前调试的类的信息,并且判断当前执行方法是否为public属性,不是的话抛出异常,是的话,便调用invoke方法执行类方法,接下里便是自己的代码了,同时注意的是在解析sql语句的时候执行的tp里的方法。
ok,流程跑了一遍,自己感觉清晰多了,以前就是在项目里写代码,从不看tp的源代码的,今天过了下,感觉良好,下次多过几遍,把里面的精髓掌握住,就写到这里。
来源:http://blog.csdn.net/molaifeng/article/details/THINKPHP怎么设置页面加载时间 - ThinkPHP框架
因为页面加载时间默认是30秒!我怎么可以设置让他再长点!
积分:1200
ThinkPHP 是一个免费开源的,快速、简单的面向对象的 轻量级PHP开发框架 ,创立于2006年初,遵循Apache2开源协议发布,是为了敏捷WEB应用开发和简化企业应用开发而诞生的。ThinkPHP从诞生以来一直秉承简洁实用的设计原则,在保持出色的性能和至简的代码的同时,也注重易用性。并且拥有众多的原创功能和特性,在社区团队的积极参与下,在易用性、扩展性和性能方面不断优化和改进,已经成长为国内最领先和最具影响力的WEB应用开发框架,众多的典型案例确保可以稳定用于商业以及门户级的开发。

我要回帖

更多关于 华为手机推荐性价比高 的文章

 

随机推荐