{"id":19725397,"url":"https://github.com/easychen/lazyphp","last_synced_at":"2025-04-05T03:06:13.115Z","repository":{"id":2709414,"uuid":"3703566","full_name":"easychen/LazyPHP","owner":"easychen","description":"轻框架。包含一个前端控制器，20个常用函数和用于页面布局的Layout系统，10分钟即可学会。LP采用BSD开源协议，在代码内保留框架名即可随意商用。","archived":false,"fork":false,"pushed_at":"2019-07-13T15:20:54.000Z","size":462,"stargazers_count":567,"open_issues_count":7,"forks_count":195,"subscribers_count":78,"default_branch":"master","last_synced_at":"2025-03-29T02:03:48.257Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://ftqq.com/lazyphp/","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"libimobiledevice/libplist","license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/easychen.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-03-13T05:24:03.000Z","updated_at":"2025-03-25T15:34:07.000Z","dependencies_parsed_at":"2022-08-28T18:53:07.000Z","dependency_job_id":null,"html_url":"https://github.com/easychen/LazyPHP","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/easychen%2FLazyPHP","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/easychen%2FLazyPHP/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/easychen%2FLazyPHP/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/easychen%2FLazyPHP/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/easychen","download_url":"https://codeload.github.com/easychen/LazyPHP/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247280263,"owners_count":20912967,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-11T23:29:35.724Z","updated_at":"2025-04-05T03:06:13.089Z","avatar_url":"https://github.com/easychen.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"⚠️ 此项目已经停止维护，请使用 https://github.com/easychen/lazyphp4\n\n# LAZYPHP简介\n\nLazyPHP（以下简称LP）是一个轻框架.\n\n之所以开发这么一个框架，是因为其他框架给的太多。在高压力的情况下，ORM和盘根错节的对象树反而将简单的页面请求处理复杂化，在调试和性能上带来反面效果。\n\nLP采用函数式接口封装对象，对内通过面向对象实现代码重用，对外则提供简明扼要的操作函数。开发者甚至不用理解面向对象就能很好的使用，这让一些初级程序员很容易就开发出强壮的应用。\n\n在数据库等模块的加载上，LP采用LazyLoad方式，并用$GLOBALS实现全局单件，在方便和高效之间找到了一个平衡点。这也是LP框架名字中Lazy的来源。\nLP在新浪大量使用已经将近3年，每天承载的请求达千万级别。由于LP易读易学，使用LP的开发者之间沟通非常容易，而新同事也可以很快融入进来。\n\nLP3是LP最新的版本，最主要的调整是重新定义了Layout规则，以应对日益增多的Ajax，Mobile和Rest请求。同样是由于这个原因，LP3和之前的版本不兼容，我们建议大家在新项目中采用LP3。\n\n# LP3 实例\n基于LP3的全平台开源项目 团队效率工具 TeamToy  http://tt2net.sinaapp.com/\n\n# LP3简明教程\n\nLP是一个轻框架。它只是打算帮你处理掉每个Web应用都需要重新开始的那部分东西，并不打算成为一个大而全的Lib（我说的真的不是ZendFrameWork）。\n\nLP只包含一个FrontController+Layout系统+20个常用函数。你只需要花上10分钟了解这些东西，就能完全得掌握LP。\n\n## FRONTCONTROLLER\nFrontController（以下简称FC）翻译过来叫前端控制器，在LP中，所有的动态请求（不包括静态文件）都会经过FC。使用FC的好处是可以统一控制全部请求，举例而言，你只需要在FC中添加几行代码，就可以精确控制哪些controller和action不可以访问。\n\nLP3的FC你可以看成就是ROOT/index.php(实际上分发逻辑在_lp/lp.init.php),所有的请求都在这里处理。不管你是用户登录还是浏览文章，在LP上用户访问的页面都是index.php。\n\nFC根据Controller和Action对请求进行分组，并调用对应的模块来进行处理。如何定义Controller和Action？最简单的办法是把一个数据表对应到一个Controller，而对这个数据表的相关操作自然就成为了Action。\n\n比如，我们会定义一个叫做User的Controller，而把Login，Logout，Detail 作为User的Action。\n\n我们在访问LP时，把要请求的Controller和Action通过参数c和a传递给FC。\n\n```php\n/index.php?c=user\u0026a=login\n```\n\n上边这个访问告诉FC去加载名为User的Controller，并调用名为Login的方法。\n\n在实现上，Controller被放到AROOT.controller目录下，以Class形式存在，而Action就是这个Class的一个方法。\n\n下边几行伪代码描述了这个其实很简单的过程：\n\n```php\n// FC取得参数\n$c = $_REQUEST['c'] ;\n$a = $_REQUEST['a'] ;\n\n// controller文件名和Class名\n$cont_file = AROOT . ‘controller/’ . $c . ‘/’ . $a . ‘.class.php’;\n$class_name =$c .’Controller’ ;\n\n// 载入文件\nrequire_once( $cont_file );\n\n// 调用方法\n$o = new $class_name;\ncall_user_func( array( $o , $a ) );\n```\n\n实际上，编写应用的过程就是不断的添加Controller和Action并把它实现。\n\n下边是一个Controller Class的样子：\n\n```php\nclass defaultController extends appController\n{\n\tfunction __construct()\n\t{\n\t\tparent::__construct();\n\t}\n\n\tfunction index()\n\t{\n\t\t$data['title'] = $data['top_title'] = ‘首页’;\n\t\trender( $data );\n\t}\n}\n```\n\n## MVC和LAYOUT\nLP是遵循MVC模式的，它的业务逻辑和显示逻辑是完全分离的。Controller处理了业务逻辑，我们使用模板来处理显示逻辑。\n\nLP所有的模板都被放在AROOT.view下边，通过在Controller中使用Render函数来渲染模板。\n\n以下是Render函数的伪代码：\n\n```php\nfunction render( $data = NULL , $layout = NULL , $sharp = ‘default’ )\n{\n$layout_file = AROOT . ‘view/layout/’ . $layout . ‘/’ . $sharp . ‘.tpl.html’;\n@extract( $data );\nrequire( $layout_file );\n}\n```\n\n可以看到，Render接受一个$data数组，然后将数组中的数据extract出来，这样一个原本是$data['user']的数据在模板里边就能通过$user访问了。而载入模板部分更简单，只是直接require。这是因为LP直接使用PHP来做模板的解释引擎。我们推荐大家在模板中采用PHP的短标签语法以保持高的可读性：\n\n```php\n\u003c?php if( $user['level'] \u003e= 9 ): ?\u003e\n亲，你是鹳狸猿\n\u003c?php else: ?\u003e\n亲，你是平民，天黑请闭眼\n\u003c?php endif; ?\u003e\n```\n\n上边是一个使用短标签的模板的例子。if，foreach都可以这样写。切忌在模板中使用{}，这会让你的模板看起来很奇葩。\n\n为了实现模板的重用，我们引入了Layout系统。\n\n来看一个经常遇到的例子，网站头部导航和页脚版权部分的重用。\n\n最简单和最容易想到的处理办法是这样的：将头部保存为header.tpl.html，将页脚保存为footer.tpl.html。然后直接在模板中用include函数载入即可。\n\n这样很OK，但是当我们有10个模板要处理的时候，你会发现每个模板都要去include header和footer。而在这些模板中，header和footer其实是不变的，变的是中间的部分。\n\n于是我们为这些相同模板建立一个通用的模板文件，叫做sharpA.tpl.html，在styleA中我们指定好header和footer，然后sharpA根据FC接收到的C和A变量（还记得吧）去加载对应子目录下模板。这样我们只需要创建C和A对应的模板就可以了。下边是一个典型的sharp模板。\n\u003cpre\u003e\n\u0026lt;html\u0026gt;\n\u0026lt;body\u0026gt;\n\u0026lt;div id=\"hd\" \u0026gt;\u0026lt;?php @include_once( dirname(__FILE__) ) . DS . 'header.tpl.html'; ?\u0026gt;\u0026lt;/div\u0026gt;\n\n\u0026lt;div id=\"bd\"\u0026gt;\n\u0026lt;div id=\"side\"\u0026gt;\n\u0026lt;?php\ninclude( AROOT . 'view' . DS . 'layout' . DS . g('layout') . DS . 'side' . DS . g('c') . DS . g('a') . '.tpl.html' );\n\n?\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;div id=\"main\"\u0026gt;\n\u0026lt;?php\ninclude( AROOT . 'view' . DS . 'layout' . DS . g('layout') . DS . 'main' . DS . g('c') . DS . g('a') . '.tpl.html' );\n?\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\n\u0026lt;div id=\"ft\"\u0026gt;\u0026lt;?php @include_once( dirname(__FILE__) ) . DS . 'footer.tpl.html'; ?\u0026gt;\u0026lt;/div\u0026gt;\n\n\u0026lt;/body\u0026gt;\n\u0026lt;/html\u0026gt;\n\u003c/pre\u003e \n\n当一个sharp满足不了需求时，我们可以再创建sharpB.tpl.html。styleB可以选择性的共享sharpA的header和footer，也可以载入自己特定的header。我们把sharpA，sharpB…等通用模板放到一个目录下，叫做一个Layout。\n\n目前Layout按照访问方式分为Web，Ajax，Mobile和Rest四种。当你为你的游戏机或者电视机创建一组特定风格的sharp模板时，你可以创建一个名叫TV或者PFP的Layout目录。\n\n切换Sharp和Layout非常简单，只需要修改Render函数中第二和第三个参数就可以了。在没有指定的情况下，LP3会启用Layout下的default sharp模板，同时还会根据请求的方式，自动加载Web，Mobile或者Ajax Layout。\n\n再回过头来说MVC，我们已经了解了C和V在LP的使用。而M就是根据请求参数，从数据库或者其他地方取得数据的过程。在LP3之前，数据是直接在Controller中查询数据库取得的。\n\n```php\nfunction show()\n\n{\n\n$uid =  intval($_REQUEST['uid']);\n\nif( $uid \u003c 1 ) return info_page(‘错误的uid’);\n\n$data['user'] = get_line( “SELECT * FROM `user` WHERE `uid` = ‘” . $uid . “‘ LIMIT 1″ );\n\nrender( $data );\n\n}\n\n```\n\n这种方式将SQL散落在各个Action中，不利于重用和修改。所以在LP3中，我们采用专门的model文件来放置Controller中用到的数据操作函数。还是用上边的例子，我们假设这是一个名为User的Controller的Show Action。那么在LP3中我们推荐的做法如下：\n\n首先在 AROOT/model目录下创建一个名为user.function.php的文件。\n\n然后在文件中写入获取用户信息的函数：\n\n```php\nfunction get_user_info_by_id( $uid )\n\n{\n\nreturn get_line( “SELECT `name` ,`email` , `bod` FROM `user` WHERE `uid` = ” . intval($uid) . ” LIMIT 1 ” )\n\n}\n```\n\nuser.function.php将在请求参数包含?c=user 时自动加载。所以我们可以把show改为下边的样子：\n\n```php\nfunction show()\n\n{\n\n$uid =  intval($_REQUEST['uid']);\n\nif( $uid \u003c 1 ) return info_page(‘错误的uid’);\n\n$data['user'] = get_user_info_by_id(  $uid  );\n\nrender( $data );\n\n}\n```\n\n这样在其他的Action，比如User/settings 中，我们可以通过get_user_info_by_id 函数重用代码。通过函数封装重复SQL还有一个好处是方便对SQL进行统一处理，加手工Cache就是一个经常能遇到的需求。\n\n## 常用函数\nLP3中的函数主要有3类，迅捷函数，功能函数和数据库函数，一共20个左右。\n\n### 迅捷函数\n\n迅捷函数是一系列的函数缩写：\n\n\u003cpre\u003e\nfunction c( $str ) // 读取配置文件中$str为key的对应的value\nfunction v( $str ) // 取得 $_REQUEST[$str] 的数据，不存在不会报warning\nfunction z( $str ) // strip_tags\nfunction g( $str ) // 取得 $GLOBALS[$str] 的数据\nfunction t( $str ) // trim\nfunction u( $str ) // urlencode\n\u003c/pre\u003e\n\n### 功能性函数\n\n\u003cpre\u003e\nfunction render( $data = NULL , $layout = NULL , $style = ‘default’ ) // Layout\nfunction info_page( $info ) // 系统提示信息\nfunction ajax_echo( $info ) // 输出提示信息，包含永不过期的header\nfunction uses( $file ); // 载入lib目录下的文件\n\u003c/pre\u003e\n\n### 数据库函数\n\n\u003cpre\u003e\nfunction s( $str , $db = NULL ) // mysql_real_escape_string\nfunction prepare( $sql , $array ) // 将数组中的变量顺序替换SQL中的？\nfunction db() // 使用config目录下的数据库设置,创建并返回数据库链接\nfunction get_data( $sql , $db = NULL ) // 以二维数组的方式返回$sql对应的结果\nfunction get_line( $sql , $db = NULL ) // 以一维数组的方式返回$sql对应的单行结果\nfunction get_var( $sql , $db = NULL ) // 以变量的方式返回一个数值\nfunction last_id( $db = NULL ) // last id\nfunction run_sql( $sql , $db = NULL ) // 运行sql,不返回结果集\nfunction db_error() // 数据库错误信息\nfunction db_errno() // 数据库错误编号\nfunction close_db( $db ) // 显式关闭数据库链接\n\u003c/pre\u003e\n\n### 特别说明\n\n其中要详细说明的有两个：\n\n#### C($KEY)和配置文件\n\nLP将应用配置信息保存在AROOT/config/app.config.php下，使用$GLOBALS['config']超全局变量以数组形式保存。使用c($key)的方式，可以在MVC各个地方获取。\n\n#### PREPARE()函数\n\n这个函数是LP3新引入的，主要是希望减少SQL注入的问题。使用方式如下：\n\n\u003cpre\u003e\necho $sql = prepare( “SELECT * FROM `user` WHERE `name` = ?s AND `uid` = ?i AND `level` = ?s LIMIT 1″ , array( “Easy’” , ‘-1′, ’9.56′ ) );\n\u003c/pre\u003e\n\n输出结果为：\n\n\u003cpre\u003e\nSELECT * FROM `user` WHERE `name` = ‘Easy\\” AND `uid` = ‘-1′ AND `level` = ’9.56′ LIMIT 1\n\u003c/pre\u003e\n\n使用prepare函数时要注意：SQL必须使用双引号，【?i】表示整数，【?s】表示整数以外的其他值。prepare会无例外的mysql_real_escape_string，然后在两边加上单引号。\n\n## CSS，JAVASCRIPT和AJAX\n\nLP3采用BootStrap这个流行的前端框架，[你可以从这里看到它的详细介绍](http://twitter.github.com/bootstrap/)。\n\nJavaScript库上，LP3开始换为JQuery。[这里是JQuery API的参考手册](http://api.jquery.com/)。\n\n为了方便不熟悉的同学也能使用好Ajax，LP3自己实现了Ajax传输数据的JS函数。这些函数都放在AROOT/static/script/app.js中。\n\n```javascript\n$(‘#标签ID’).load(‘URL’);  // 是由JQuery自身实现的，可以方便的无刷新载入页面。\n\nsend_form_in( ‘FROMID’ ); // 将form表单中的数据通过Ajax提交（file类型除外），并将服务器返回的HTML显示在Form表单顶部\n\nsend_form_pop(‘FROMID’); //  将form表单中的数据通过Ajax提交（file类型除外），并将服务器返回的HTML显示在浮动图层中\n```\n\n好了，这里就是关于LP3 的一切了，希望LP3能让你更快的完成工作。\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feasychen%2Flazyphp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feasychen%2Flazyphp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feasychen%2Flazyphp/lists"}