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); } } ?>