php 魔鬼训练
环境配置
找到自己的【系统命令行】目录:bin
/usr/bin #mac系统
/bin #ubuntu系统
再找到Php的编译器,这个根据你的安装路径来判断,mac默认的路径如下
cd /usr/bin #mac系统默认路径
cd /usr/local/php/bin/ #我的ubuntu中php的安装路径
./php -v #测试
新建php文件命名为lee(注意,#! 后面的参数是你的php编译器路径,这里我使用了mac自带的php编译器。这样一来,无论将文件放置在哪里,都可以用php编译器来运行该文件)
#! /usr/bin/php
<?php
echo "I am god".PHP_EOL;
?>
将lee复制到【系统命令行】目录中
sudo cp ./lee /usr/bin #mac系统的Bin的路径
这样一来,无论在什么路径下载命令行中输入:lee 都可以输出“I am god”
完成了自己的命令行
正式开始
demo1
知识点:
&& 这里并不是并且的意思,而是表达式如果成立,则执行后面的语句
PHP_EOL 这里是换行的意思。因为Linux和window换行的语法不一样【\n和\r\n】,所以使用这种写法统一
#! /usr/bin/php
<?php
echo "I am god".PHP_EOL;
$result = '';
if($argc > 1) //执行lee时,自己算是一个参数,所以如果有第二个参数就一定是大于1的
{
'-v' == $argv[1] && $result = 'god version is 1.0';
} $result != '' && exit($result.PHP_EOL);
?>
demo2:
新建类库lee_class
知识点: fgets(STDIN) 获取用户键盘输入
<?php
class lee
{
static $VERSION = 'god version is 1.1';
static $project_name = ''; //项目名称
static $project_author = ''; //项目作者 static function init()
{
echo "input your project name : ";
self::$project_name = fgets(STDIN); echo "input your author name : ";
self::$project_author = fgets(STDIN); return 'lee init complete';
}
}
?>
修改lee
#! /usr/bin/php
<?php
require('lee_func');
require('lee_class');
$result = '';
if($argc > 1)
{
'-v' == $argv[1] && $result = lee::$VERSION;
'init' == $argv[1] && $result = lee::init();
}
$result != '' && exit($result.PHP_EOL);
echo 'I am god'.PHP_EOL;
?>
demo3:
修改lee_class
知识点:__callStatic 未定义的静态函数调用时,会触发该函数
<?php
require('lee_config');
class lee
{
static $v = 'god version is 1.2';
static function init()
{
$lee_config = new lee_config(); echo "input your project name : ";
$lee_config->project_name = fgets(STDIN);//项目名称 echo "input your author name : ";
$lee_config->project_author = fgets(STDIN);//项目作者 $json = json_encode($lee_config); return file_put_contents(getcwd().'/god.json',$json).' of bytes is written'.PHP_EOL.'god config is created';
} //未定义的静态函数调用时,会触发该函数
static function __callStatic($m,$static_func)
{
exit("static function '{$m}' is not define".PHP_EOL);
}
}
?>
添加类lee_config
<?php class lee_config
{
//项目名称
public $project_name; //项目作者
public $project_author;
} ?>
修改lee (添加了php版本的“反射”来动态获取用户输入并且转换为属性或者方法)
知识点:利用php版本的“反射”来动态获取用户输入并且转换为属性或者方法
#! /usr/bin/php
<?php
require('lee_class');
$result = '';
if($argc > 1)
{
$p = $argv[1];
if(substr($p, 0,1) == '-')
{
//有'-'说明是属性,利用php版本的“反射”获取属性,当然还要判断一下属性是否存在
$p = substr($p,1);
//由于属性的调用格式是$name,所以这里有两个$,
$result = isset(lee::$$p)?lee::$$p:"command -{$p} is undefind";
}
else
{
//否则就是方法或者事件,利用php版本的“反射”获取方法,当然还要判断一下方法是否存在
$result = lee::$p();
}
}
$result != '' && exit($result.PHP_EOL);
?>
demo4:生成项目雏形
修改lee_class
<?php
require('lee_config');
class lee
{
static $v = 'god version is 1.2';
static function init()
{
$lee_config = new lee_config(); echo "input your project name : ";
$lee_config->project_name = fgets(STDIN);//项目名称 echo "input your author name : ";
$lee_config->project_author = fgets(STDIN);//项目作者 $json = json_encode($lee_config); return file_put_contents(getcwd().'/lee.json',$json).' of bytes is written'.PHP_EOL.'god config is created';
} static function config()
{
$json = file_get_contents(getcwd().'/lee.json');
$obj = json_decode($json);
$result = '';
foreach ($obj as $key => $value) {
$result .= $key.' = '.$value.PHP_EOL;
}
return $result;
} static function make()
{
$json = file_get_contents(getcwd().'/lee.json');
$obj = json_decode($json);
!file_exists(getcwd().'/'.$obj->project_name) && mkdir(getcwd().'/'.$obj->project_name);
} //未定义的静态函数调用时,会触发该函数
static function __callStatic($m,$static_func)
{
exit("static function '{$m}' is not define".PHP_EOL);
}
}
?>
demo5:加强骨架
添加类lee_frame,专门管理骨架
<?php
class lee_frame
{
public $folder = ""; //项目文件夹
public $entry = ""; //入口文件
function __construct($name)
{
$this->folder = getcwd().'/'.$name;
$this->entry = $this->folder.'/index.php';
} function run()
{
!file_exists($this->folder) && mkdir($this->folder); //创建项目文件夹
!file_exists($this->entry) && file_put_contents($this->entry,''); //创建项目入口
}
}
?>
优化了config的名称,修改一下lee_class和lee_config
<?php
require('lee_config');
class lee
{
static $v = 'god version is 1.2';
static function init()
{
$lee_config = new lee_config(); echo "input your project name : ";
$lee_config->name = fgets(STDIN);//项目名称 echo "input your author name : ";
$lee_config->author = fgets(STDIN);//项目作者 $json = json_encode($lee_config); return file_put_contents(getcwd().'/lee.json',$json).' of bytes is written'.PHP_EOL.'god config is created';
} static function config()
{
$json = file_get_contents(getcwd().'/lee.json');
$obj = json_decode($json);
$result = '';
foreach ($obj as $key => $value) {
$result .= $key.' = '.$value.PHP_EOL;
}
return $result;
} static function make()
{
$json = file_get_contents(getcwd().'/lee.json');
$obj = json_decode($json);
require('lee_frame');
$lee_frame = new lee_frame($obj->name);
$lee_frame->run();
} //未定义的静态函数调用时,会触发该函数
static function __callStatic($m,$static_func)
{
exit("static function '{$m}' is not define".PHP_EOL);
}
}
?>
简化了名称lee_config
<?php class lee_config
{
//项目名称
public $name; //项目作者
public $author;
} ?>
demo6:继续加强骨架
将lee_frame搬家到更深的目录,同时也是为了优化框架和学习命名空间
core\frame\lee_frame
知识点:命名空间,在不同的命名空间下可以定义同名的类。但是注意有个致命,这样一来所有new class的类实例化,默认都会加上命名空间,最简单的解决方法就是:new \class
<?php
namespace core\frame;
class lee_frame
{
public $folder = ""; //项目文件夹
public $entry = ""; //入口文件
function __construct($name)
{
$this->folder = getcwd().'/'.$name;
$this->entry = $this->folder.'/index.php';
} function run()
{
!file_exists($this->folder) && mkdir($this->folder); //创建项目文件夹
!file_exists($this->entry) && file_put_contents($this->entry,''); //创建项目入口
}
}
?>
修改lee_class
知识点:1、__autoload 如果new未找到的类,会触发这个函数
2、use core\frame\lee_frame 加载命名空间,这样一来所有lee_frame的类,都只会加载命名空间为core\frame的类了
<?php
require('lee_config');
use core\frame\lee_frame;
//如果new未找到的类,会触发这个函数
function __autoload($className)
{
$className = str_replace('\\', '/', $className);
require($className);
} class lee
{
static $v = 'god version is 1.2';
static function init()
{
$lee_config = new lee_config(); echo "input your project name : ";
$lee_config->name = str_replace("\n","",fgets(STDIN)); //项目名称 echo "input your author name : ";
$lee_config->author = str_replace("\n","",fgets(STDIN)); //项目作者 $json = json_encode($lee_config); return file_put_contents(getcwd().'/lee.json',$json).' of bytes is written'.PHP_EOL.'god config is created';
} static function config()
{
$json = file_get_contents(getcwd().'/lee.json');
$obj = json_decode($json);
$result = '';
foreach ($obj as $key => $value) {
$result .= $key.' = '.$value.PHP_EOL;
}
return $result;
} static function make()
{
$json = file_get_contents(getcwd().'/lee.json');
$obj = json_decode($json);
$lee_frame = new lee_frame($obj->name);
$lee_frame->run();
} //未定义的静态函数调用时,会触发该函数
static function __callStatic($m,$static_func)
{
exit("static function '{$m}' is not define".PHP_EOL);
}
}
?>
demo7:渲染Php模板
修改lee_class
知识点:将变量赋值给类中的属性,在php中,哪怕属性没有在类中初始化/定义,那么在赋值的时候也可以当场定义的。
<?php
require('lee_config');
use core\frame\lee_frame;
//如果new未找到的类,会触发这个函数
function __autoload($className)
{
$className = str_replace('\\', '/', $className);
require($className);
} class lee
{
static $v = 'god version is 1.2';
static function init()
{
$lee_config = new lee_config(); echo "input your project name : ";
$lee_config->name = str_replace("\n","",fgets(STDIN)); //项目名称 echo "input your author name : ";
$lee_config->author = str_replace("\n","",fgets(STDIN)); //项目作者 $json = json_encode($lee_config); return file_put_contents(getcwd().'/lee.json',$json).' of bytes is written'.PHP_EOL.'god config is created';
} static function config()
{
$json = file_get_contents(getcwd().'/lee.json');
$obj = json_decode($json);
$result = '';
foreach ($obj as $key => $value) {
$result .= $key.' = '.$value.PHP_EOL;
}
return $result;
} static function make()
{
$json = file_get_contents(getcwd().'/lee.json');
$obj = json_decode($json);
$lee_frame = new lee_frame($obj->name);
$lee_frame->name = $obj->name; //将项目名传入类中
$lee_frame->author = $obj->author; //将作者名传入类中
$lee_frame->run();
} //未定义的静态函数调用时,会触发该函数
static function __callStatic($m,$static_func)
{
exit("static function '{$m}' is not define".PHP_EOL);
}
}
?>
新增index.tpl
知识点:奇思淫巧
<?php echo '<?php'.PHP_EOL; ?>
/**
* name:<?php echo $name; ?>
* User: <?php echo $author.PHP_EOL;; ?>
* Date: <?php ini_set('date.timezone','Asia/Shanghai'); echo date('Y-m-d') ?>
*/
echo "hello world";
修改lee_frame
知识点:extract(get_object_vars($this)); //这个东西比较复杂,首先将指定的类中的属性化为一个数组,然后extract解析数组
<?php
namespace core\frame;
class lee_frame
{
public $folder = ""; //项目文件夹
public $entry = ""; //入口文件
function __construct($name)
{
$this->folder = getcwd().'/'.$name;
$this->entry = $this->folder.'/index.php';
} function run()
{
//创建项目文件夹(如果不存在)
!file_exists($this->folder) && mkdir($this->folder);
//打开缓存区,不让内容输出到界面去
ob_start();
//这个东西比较复杂,首先将指定的类中的属性化为一个数组,然后extract解析数组
extract(get_object_vars($this));
//获取模板内容(需要好好研究学习一下模板的小技巧)
include dirname(__FILE__).'/tpl/index.tpl';
//获取缓冲区的内容
$contents = ob_get_contents();
//关闭并且清除缓冲区
ob_end_clean();
//创建项目入口(覆盖)
file_put_contents($this->entry,$contents);
}
}
?>
demo8 : 开启php内置的服务器
#套路
php -S localhost:9900 -t 目录 #demo
/usr/bin/php -S localhost:9900 -t /Users/apple/Desktop/lee/test
demo9
修改lee_frame
知识点:1、反射
2、get_defined_functions 获取所有已定义的变量
3、get_defined_functions 获取所有函数(包含内置和自定义)
4、文件操作 scandir
<?php
namespace core\frame;
class lee_frame
{
public $folder = ""; //项目文件夹
public $entry = ""; //入口文件
function __construct($name)
{
$this->folder = getcwd().'/'.$name;
$this->entry = $this->folder.'/index.php';
} function compile()
{
//获取项目/code下所有的文件
$_files = scandir($this->folder.'/code');
foreach($_files as $_file)
{
//匹配如aaa.var.php的文件
if(preg_match("/\w+\.var|func\.php$/i", $_file))
{
require($this->folder.'/code/'.$_file);
}
} unset($_files); //摧毁变量,仅仅是为了下面的get_defined_vars
unset($_file); //摧毁变量,仅仅是为了下面的get_defined_vars $var_results = var_export(get_defined_vars(),true);
$result = '<?php'.PHP_EOL
."extract({$var_results})"; file_put_contents($this->folder.'/vars', $result); //获取所有自定义函数
$func_results = get_defined_functions()['user']; //拼接的函数字符串
$func_str = '<?php '.PHP_EOL
."/*".PHP_EOL
."* compile by lee {date(Y-m-d h:i:s)}".PHP_EOL
.'*/'.PHP_EOL; foreach ($func_results as $func)
{
//反射
$f = new \ReflectionFunction($func);
$start=$f->getStartLine(); //函数所在文件位置的起始行
$end=$f->getEndLine(); //函数所在文件位置的结束行
$file_arr = file($f->getFileName()); //根据路径获取所有的内容,根据内容的换行作为数组的索引
$func_arr = array_slice($file_arr, $start - 1,$end - $start + 1); //根据上面的数组,返回纯函数的行内容
$func_str .= implode($func_arr); //获取函数纯字符串
} file_put_contents($this->folder.'/functions', $func_str); } function run()
{
//创建项目文件夹(如果不存在)
!file_exists($this->folder) && mkdir($this->folder);
//打开缓存区,不让内容输出到界面去
ob_start();
//这个东西比较复杂,首先将指定的类中的属性化为一个数组,然后extract解析数组
extract(get_object_vars($this));
//获取模板内容(需要好好研究学习一下模板的小技巧)
include dirname(__FILE__).'/tpl/index.tpl';
//获取缓冲区的内容
$contents = ob_get_contents();
//关闭并且清除缓冲区
ob_end_clean();
//创建项目入口(覆盖)
file_put_contents($this->entry,$contents);
} }
?>
demo10
添加lee_mvc
<?php namespace core\frame;
class lee_mvc
{
public $classNmae = ''; //类名
public $classComment = ''; //类的注释
public $classMethods = array(); //类中所有的方法 function __construct($cname)
{
$this->classNmae = $cname;
//类反射
$f = new \ReflectionClass($cname);
//获取类的注释
$this->classComment = $f->getDocComment();
//获取类中所有的方法,返回的数组中值,实际上是反射(函数)
$this->classMethods = $f->getMethods();
} function IsController()
{
return preg_match('/@Controller/', $this->classComment);
} function getRequestMapping()
{
$arr1 = array();
foreach ($this->classMethods as $value) {
//获取类方法的注释
$arr2 = $this->getRequestMappingResult($value);
if($arr2)
{
$arr1 = array_merge($arr1,$arr2);
}
}
return $arr1;
} function getRequestMappingResult($medhod)
{
//@RequestMapping("/getme",Method=GET);
if(preg_match('/@RequestMapping\("(.{2,50})",Method=(\w{3,8})\);/', $medhod->getDocComment(),$result))
{
$Method = $medhod->getName(); //方法名
$RequestUrl = $result[1]; //url地址
$RequestMethod = $result[2]; //post或者get
return array(
$RequestUrl => array('RequestMethod'=>$RequestMethod,'Class'=>$this->classNmae,'Method'=>$Method)
);
}
return false;
}
}
修改lee_frame
<?php
namespace core\frame;
use core\frame\lee_mvc;
ini_set('date.timezone','Asia/Shanghai'); class lee_frame
{
public $folder = ""; //项目文件夹
public $entry = ""; //入口文件
function __construct($name)
{
$this->folder = getcwd().'/'.$name;
$this->entry = $this->folder.'/index.php';
} function compile()
{
//获取项目/code下所有的文件
$_files = scandir($this->folder.'/code');
foreach($_files as $_file)
{
//匹配如aaa.var.php的文件
if(preg_match("/\w+\.var|func|class\.php$/i", $_file))
{
require($this->folder.'/code/'.$_file);
}
} unset($_files); //摧毁变量,不要污染到自定义的变量,也是为了下面的get_defined_vars
unset($_file); //摧毁变量,不要污染到自定义的变量,也是为了下面的get_defined_vars $var_results = var_export(get_defined_vars(),true);
$result = '<?php'.PHP_EOL
."extract({$var_results});"; file_put_contents($this->folder.'/vars', $result); //获取所有自定义函数
$func_results = get_defined_functions()['user']; //拼接的函数字符串
$func_str = "<?php ".PHP_EOL
."/*".PHP_EOL
."* compile by lee ".date('Y-m-d h:i:s').PHP_EOL
."*/".PHP_EOL; foreach ($func_results as $func)
{
//反射(函数)
$f = new \ReflectionFunction($func);
$start=$f->getStartLine(); //函数所在文件位置的起始行
$end=$f->getEndLine(); //函数所在文件位置的结束行
$file_arr = file($f->getFileName()); //根据路径获取所有的内容,根据内容的换行作为数组的索引
$func_arr = array_slice($file_arr, $start - 1,$end - $start + 1); //根据上面的数组,返回纯函数的行内容
$func_str .= implode($func_arr); //获取函数纯字符串
} file_put_contents($this->folder.'/functions', $func_str); //获取项目中所有的类
$class_Result = get_declared_classes();
//获取当前类名的键
$class_key = array_search(__CLASS__, $class_Result);
//我也不知道为啥排到当前类之后的类就是自定义的类,算了先写再说吧
$class_Result = array_slice($class_Result, $class_key + 1);
$arr1 = array();
foreach ($class_Result as $value)
{
$mvc = new lee_mvc($value);
if($mvc->IsController())
{
$arr2 = $mvc->getRequestMapping();
$arr1 = array_merge($arr1,$arr2);
}
} file_put_contents($this->folder.'/request_route', "<?php ".PHP_EOL." return ".var_export($arr1,true).";"); } function run()
{
//创建项目文件夹(如果不存在)
!file_exists($this->folder) && mkdir($this->folder);
//打开缓存区,不让内容输出到界面去
ob_start();
//这个东西比较复杂,首先将指定的类中的属性化为一个数组,然后extract解析数组
extract(get_object_vars($this));
//获取模板内容(需要好好研究学习一下模板的小技巧)
include dirname(__FILE__).'/tpl/index.tpl';
//获取缓冲区的内容
$contents = ob_get_contents();
//关闭并且清除缓冲区
ob_end_clean();
//创建项目入口(覆盖)
file_put_contents($this->entry,$contents); //开启我心爱的小耗子
echo "lee server is started in 9900".PHP_EOL;
system('/usr/bin/php -S localhost:9900 -t '.$this->folder);
} }
?>
php 魔鬼训练的更多相关文章
- js 魔鬼训练
1.Object.assign 偷梁换柱 / 融合 - 将多个对象合并到第一个对象中去.这样一来methods对象中就包含着data对象了.否则this无法正常访问data中的title var ne ...
- 接下来一段时间会对大家进行网络通信的魔鬼训练-理解socket
引子 下一篇标题是<深入理解MQ生产端的底层通信过程>,建议文章读完之前.或者读完之后,再读一遍我之前写的<RabbitMQ设计原理解析>,结合理解一下. 我大学时流行过一个韩 ...
- p90x 涵盖了全部方式的健身方式美国经典训练DVD
http://baike.baidu.com/view/2602721.htm p90x是美国经典训练DVD, 涵盖了全部方式的健身方式13张Beachbody P90X DVD全集,90天魔鬼训练 ...
- P3984 高兴的津津
题目描述 津津上高中了.她在自己的妈妈的魔鬼训练下,成为了一个神犇,每次参加一次OI比赛必拿Au虐全场.每次她拿到一个Au后就很高兴.假设津津不会因为其它事高兴,并且她的高兴会持续T天(包包含获奖当天 ...
- 洛谷 P3984 高兴的津津
P3984 高兴的津津 题目描述 津津上高中了.她在自己的妈妈的魔鬼训练下,成为了一个神犇,每次参加一次OI比赛必拿Au虐全场.每次她拿到一个Au后就很高兴.假设津津不会因为其它事高兴,并且她的高兴会 ...
- luogu P3984 高兴的津津
题目描述 津津上高中了.她在自己的妈妈的魔鬼训练下,成为了一个神犇,每次参加一次OI比赛必拿Au虐全场.每次她拿到一个Au后就很高兴.假设津津不会因为其它事高兴,并且她的高兴会持续T天(包包含获奖当天 ...
- 洛谷 题解 P3984 【高兴的津津】
潇洒の开始 大水题一枚/小声说话 先吐槽一下: 为什么津津经历了魔鬼训练就可以Au日常QWQ,人家也是早起晚睡的好吧 (谁说魔鬼训练就一定是早起晚睡的) 思路 津津的高兴是持续m天的,但是一旦在这m中 ...
- P1063 高兴的津津
题目描述 津津上高中了.她在自己的妈妈的魔鬼训练下,成为了一个神犇,每次参加一次OI比赛必拿Au虐全场.每次她拿到一个Au后就很高兴.假设津津不会因为其它事高兴,并且她的高兴会持续T天(包包含获奖当天 ...
- Java Web 笔记(1)
JavaWeb 学习笔记,狂神说java,链接:https://www.bilibili.com/video/av68833391 Java Web 1.基本概念 1.1.前言 web开发: web, ...
随机推荐
- codeforces 483A. Counterexample 解题报告
题目链接:http://codeforces.com/problemset/problem/483/A 题目意思:给出一个区间 [l, r],要从中找出a, b, c,需要满足 a, b 互质,b, ...
- mysql用命令行导入sql文件
前面说到了用navicat工具导入导出数据库,今天给同事导入数据库的时候,发现到不进去,好多错误,情急之下,用命令行导入的 1.打开mysql的服务.cmd-->net start mysql ...
- 学习RSA公开密钥算法
图为 RSA公开密钥算法的发明人,从左到右Ron Rivest, Adi Shamir, Leonard Adleman. 照片摄于1978年 (和讯财经原创) RSA加密算法是最常用的非对称加密算法 ...
- .net学习笔记----二级域名站点共享Session状态
前面一篇文章提到了如何在使用了ASP.NET form authentication的二级站点之间共享登陆状态, http://www.cnblogs.com/jzywh/archive/2007/0 ...
- JUC回顾之-AQS同步器的实现原理
1.什么是AQS? AQS的核心思想是基于volatile int state这样的volatile变量,配合Unsafe工具对其原子性的操作来实现对当前锁状态进行修改.同步器内部依赖一个FIFO的双 ...
- gitlab+TortoiseGit中使用SSH
1.在文件夹空白位置右键打开"Git Bash" 2.按 https://gitlab.yourhost.com/help/ssh/ssh.md 中的说明,输入命令 ssh-k ...
- Xamarin.Android开发实践(十三)
Xamarin.Android之SQLite.NET ORM 一.前言 通过<Xamarin.Android之SQLiteOpenHelper>和<Xamarin.Android之C ...
- POJ 2185 Milking Grid KMP(矩阵循环节)
Milking Grid Time Limit: 3000MS Memory Lim ...
- MATLAB中 feval 函数的用法
feval就是把已知的数据或符号带入到一个定义好的函数句柄中,你看看下面的例子 syms tf=@(x,y) x^2+y^2k1=feval(f,1,t)k2=f(1,t)k3=feval(f,1,1 ...
- Listview点击事件
listview = (ListView) findViewById(R.id.listview); // 填充data数据 data = new ArrayList<String>(); ...