lo6064200/frame

PHP 框架

Installs: 0

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

Language:CSS

Type:porject

dev-master 2018-06-21 02:52 UTC

This package is not auto-updated.

Last update: 2024-04-14 02:18:46 UTC


README

框架系统 构建属于自己的框架:c86php

目的

  • 熟悉什么是框架
  • 熟悉框架的核心运行原理
  • 熟悉与掌握框架的使用

要求

  • 框架的运行原理以及全部流程
  • 每一行代码需要加上注释
  • 不要求默打,这个难度比较大,尽量做到

需要使用的知识点

  • php
  • mysql
  • composer项目提交composer的packagist
  • git简单知识项目提交至github

准备工作

github注册账号
创建一个项目
克隆下来到www目录

安装composer

实现步骤

###1.本地创建框架的目录,使用composer init 初始化项目

    composer init初始化之后会自动声场vendor目录以及composer.json文件

###2.构建框架文件以及目录(目录名全部小写规范)

|--app                      应用目录
|    |--home                home模块
|    |    |--controller     控制器
|    |    |--view           视图
|--houdunwang               框架核心
|    |--core                核心文件
|    |--model               模型
|    |--view                视图
|--public                   
|    |--static               静态资源
|    |--view                 视图(成功提示模板)
|--system
|    |--config               配置文件
|    |--model                模型

###3.创建框架的启动类houdunwang\core\Boot.php类类名和文件名首字母大写

<?php
//命名空间
namespace houdunwang\core;
class Boot
{
    public static function run ()
        {
        echo 'run';
    }
}
<?php

namespace houdunwang\core;

class Boot
{
	public static function run ()
	{
		//错误处理
		self::handler();
		//初始化框架
		self::init();
		//执行应用
		self::appRun ();
	}

	public static function handler(){
		$whoops = new \Whoops\Run;
		$whoops->pushHandler(new \Whoops\Handler\PrettyPageHandler);
		$whoops->register();
	}
	public static function init()
	{
		session_id () || session_start ();
		date_default_timezone_set ('PRC');
	}
	public static function appRun ()
	{
		if ( isset( $_GET[ 's' ] ) ) {
			$info = explode ('/',$_GET['s']);
			$info[1] = ucfirst ($info[1]);
			$class = "\app\\{$info[0]}\controller\\{$info[1]}";
			$action = $info[2];

			define ('MODULE',strtolower ($info[0]));
			define ('CONTROLLER',lcfirst ($info[1]));
			define ('ACTION',$info[2]);
		} else {
			$class = "\app\home\controller\Entry";
			$action = "index";

			define ('MODULE','home');
			define ('CONTROLLER','entry');
			define ('ACTION',$action);
		}
		echo call_user_func_array ( [ new $class , $action ] , [] );
		exit;
	}
}

###4.在public目录中创建index.php单一入口文件

<?php
require_once '../vendor/autoload.php';
\houdunwang\core\Boot::run ();

###5.访问框架入口:http://localhost:8080/frame/public/ 这个时候报错:

Fatal error: Class 'houdunwang\core\Boot' not found in /Applications/MAMP/htdocs/frame/public/index.php on line 3

因为类加载使用时需满足:include加载文件和导入命名空间
继续往下解决这个问题 ###6.配置composer配置文件 修改composer.json文件。注意autoload该项需自己增加

{
    "name": "chaorenwubin/frame",
    "description": "后盾网c86php框架系统",
    "type": "project",
    "licence":"MIT",
    "authors": [
        {
            "name": "武斌",
            "email": "wubin.mail@foxmail.com"
        }
    ],
    "minimum-stability": "dev",
    "require": {},
    "autoload":{
        "files":[],
        "psr-4":{
           "houdunwang\\":"houdunwang\\",
           "app\\":"app\\"
        }
    }
}

PSR-4

1.是制定的代码规范,简称PSR,是代码开发的事实标准
2.PSR-4使代码更加规范,能够满足面向package的自动加载,它规范了如何从文件路径自动加载类,同时规范了自动加载文件的位置
3.如果是: "houdunwang\\":"houdunwang\\",当实例化\houdunwang\core\Boot类时,会加载houdunwang/core/Boot.php
4.如果是: "houdunwang\\":"hdphp\\",当实例化\houdunwang\core\Boot类时,hdphp/core/Boot.php
5.如果是: "houdunwang\\":"",当实例化\houdunwang\core\Boot类时,Boot.php
5.反斜线是转义

生成composer自动载入文件,在Terminal中进入项目跟目录执行:

composer dump

这时,访问项目入口public文件输出run ###7.Boot.php中书写appRun方法: 引入助手函数

1.将以前我们写的helper.php文件放入system/helper.php
2.修改composer.json文件中autoload项的files
"autoload":{
        "files":[
            "system/helper.php"
        ],
        "psr-4":{
           "houdunwang\\":"houdunwang\\",
           "app\\":"app\\"
        }
}
3.在Teminal终端执行composer dump

appRun方法具体代码

public static function appRun ()
	{
		if(isset($_GET['s'])){
			//通过?s=模块/控制器/方法(?s=home/entry/index)进行访问
			//接受get参数s,并将其转为数组
			$info = explode ('/',$_GET['s']);
			//dd($info);
			$info[1] = ucfirst ($info[1]);
			//dd($info);
			$c = "app\\{$info[0]}\controller\\{$info[1]}";
			$a  = $info[2];
			define ('MODULE',strtolower ($info[0]));
			define ('CONTROLLER',strtolower ($c));
			define ('ACTION',$a);
		}else{
			$c = "\app\home\controller\\entry";//控制器类
			$a = 'index';//方法
			define ('MODULE','home');
			define ('CONTROLLER','entry');
			define ('ACTION',$a);
		}
		return call_user_func_array ([new $c,$a],[]);
	}

###8.测试访问app中我们构建的程序 在app/home/controller中创建Entry.php

<?php

namespace app\home\controller;

class Entry
{
	public function index(){
		echo 'Welcome';
	}
}

通过地址栏访问publicpublic/index.phppublic/index.php?s=home/entry/index
也可通过尝试其他地址访问,如:public/index.php?s=home/entry/store
浏览器正常输出Welcome ###9.构建控制器层 C public/view放入message.php模板文件

自己参考代码

在 core 目录中创建Controller.php,并让app\home\controller\Entry.php及以后类继承Controller

<?php

namespace houdunwang\core;

class Controller
{
	private $url;

	protected function message($msg){
		include './view/message.php';
		exit;
	}

	protected function setRedirect($url = ''){
		if($url){
			$this->url = "location.href='$url'";
		}else{
			$this->url = "window.history.back()";
		}
		return $this
	}
}

app/controller/Entry.php,中增加store方法进行测试,增加store方法进行测试
通过地址栏访问store方法:public/index.php?s=home/entry/store
可看到提示页面,3秒之后自动跳转

<?php

namespace app\home\controller;

use houdunwang\core\Controller;

class Entry extends Controller
{
	public function index(){
		echo 'Welcome';
	}

	public function store(){
		$this->setRedirect ('?s=home/entry/index')->message ('添加成功');
	}
}

###10.构建视图层 V 在core/view目录中建立View.php和Base.php
View.php

<?php

namespace houdunwang\view;

class View
{
	public function __call ( $name , $arguments )
	{
		// TODO: Implement __call() method.
		return self::parseAction ( $name , $arguments );
	}

	public static function __callStatic ( $name , $arguments )
	{
		// TODO: Implement __callStatic() method.
		return self::parseAction ( $name , $arguments );
	}

	public static function parseAction ( $name , $arguments )
	{
		return call_user_func_array ( [ new Base , $name ] , $arguments );
	}
}

Base.php

<?php

namespace houdunwang\view;

class Base
{
	private $file;
	private $data;

	public function make ()
	{
		
		$this->file = "../app/" . MODULE . '/view/' . CONTROLLER . '/' . ACTION . '.php';

		return $this;         
	}

	public function with ( $var )
	{
		$this->data = $var;

		return $this;
	}
	
	//当输出对象的时候出发,比如说echo $obj->make();
	public function __toString ()
	{
		// TODO: Implement __toString() method.
		extract ($this->data);
		include $this->file;
		return '';
	}
}

###11构建模型层和数据库ORM数据对象关系映射 数据库配置项文件system/config/database.php

<?php
return [
	'driver'=>'mysql',
	'host'     => '127.0.0.1',
	'user'     => 'root',
	'password' => 'root',
	'dbname'     => 'c86',
];

system/helper.php助手函数中增加加载配置项的c函数

function c ( $path )
	{
		$info   = explode ( '.' , $path );
		$config = include "../system/config/" . $info[ 0 ] . '.php';

		return isset( $config[ $info[ 1 ] ] ) ? $config[ $info[ 1 ] ] : null;

	}

houdunwang/model/Model.php

<?php

namespace houdunwang\model;


class Model
{
	/**
	 * @param $name
	 * @param $arguments
	 */
	public function __call ( $name , $arguments )
	{
		// TODO: Implement __call() method.
		return self::parseAction ( $name , $arguments );
	}

	/**
	 * @param $name
	 * @param $arguments
	 */
	public static function __callStatic ( $name , $arguments )
	{
		// TODO: Implement __callStatic() method.
		return self::parseAction ( $name , $arguments );
	}

	/**
	 * @param $name
	 * @param $arguments
	 *
	 * @return mixed
	 */
	public static function parseAction ( $name , $arguments )
	{
		$class = get_called_class ();
		return call_user_func_array ( [ new Base($class) , $name ] , $arguments );
	}
}

base.php

<?php

namespace houdunwang\model;

use PDO;
use PDOException;
use Exception;

/**
 * 模型基础类
 * Class Base
 *
 * @package houdunwang\model
 */
class Base
{
	protected $table;
	protected $pdo;
	private   $where = '';
	private   $field = '';

	public function __construct ( $class )
	{
		//1.链接数据库
		$this->connect ();
		//$class打印结果:system\model\Article
		$class       = explode ( '\\' , $class );
		$this->table = strtolower ( $class[ 2 ] );
	}

	private function connect ()
	{
		$dsn      = c ( 'database.driver' ) . ":host=" . c ( 'database.host' ) . ";dbname=" . c ( 'database.dbname' );
		$user     = c ( 'database.user' );
		$password = c ( 'database.password' );
		try {
			$this->pdo = new PDO( $dsn , $user , $password );//链接数据库
			$this->pdo->query ( 'SET NAMES UTF8' );//设置字符集
			//设置错误属性
			$this->pdo->setAttribute ( PDO::ATTR_ERRMODE , PDO::ERRMODE_EXCEPTION );
		} catch ( PDOException $e ) {
			//输出错误
			exit( $e->getMessage () );
		}
	}


	/**
	 * 获取单一数据
	 *
	 * @param $pk    主键值
	 */
	public function find ( $pk )
	{
		//获得主键
		$priKey = $this->getPk ();
		//组合where条件,调用where方法
		$this->where ( "{$priKey}={$pk}" );
		//组合sql语句
		$field = empty( $this->field ) ? '*' : $this->field;
		$sql   = "select {$field} from {$this->table} {$this->where}";
		//执行查询
		$data = $this->query ( $sql );
		if ( $data ) {
			//存储到data属性,使用toarray方法获得数据
			$this->data = current ( $data );

			return $this;
		}

		return [];
	}

	/**
	 * 获取全部数据
	 *
	 * @return $this|array
	 */
	public function get ()
	{
		$field = empty( $this->field ) ? '*' : $this->field;
		$sql   = "select {$field} from {$this->table}";
		$data  = $this->query ( $sql );
		if ( $data ) {
			$this->data = $data;

			return $this;
		}

		return [];
	}

	/**
	 * 删除操作
	 *
	 * @return bool
	 */
	public function destory ()
	{
		//没有where条件不能执行删除
		if ( empty( $this->where ) )
			return false;
		$sql = "delete from {$this->table} {$this->where}";

		return $this->exec ( $sql );
	}

	/**
	 * 更新数据
	 *
	 * @param $data
	 *
	 * @return bool
	 */
	public function update ( array $data )
	{
		//更新的时候没有where条件不允许更新
		if ( empty( $this->where ) )
			return false;
		$fields = '';
		foreach ( $data as $k => $v ) {
			$fields .= "{$k}='{$v}',";
		}
		//将最后,去掉
		$fields = rtrim ( $fields , ',' );
		$sql    = "update {$this->table} set {$fields} {$this->where}";

		//执行sql语句
		return $this->exec ( $sql );
	}

	/**
	 * 数据写入
	 *
	 * @param array $data
	 *
	 * @return mixed    返回自增id
	 */
	public function insert ( array $data )
	{
		$fields = '';
		$values = '';
		foreach ( $data as $field => $value ) {
			$fields .= "$field,";
			$values .= is_int ( $value ) ? "$value," : "'$value',";
		}
		//将最后侧的,去掉
		$fields = rtrim ( $fields , ',' );
		$values = rtrim ( $values , ',' );
		//insert into article (atitle,time) values ('hello',180);
		$sql = "insert into {$this->table} ($fields) values ($values)";

		return $this->exec ( $sql );
	}

	/**
	 * 查询数据获取制定字段
	 *
	 * @param $data
	 *
	 * @return $this
	 */
	public function field ( $data )
	{
		$this->field = $data;

		return $this;
	}

	/**
	 * 统计
	 * @return mixed
	 */
	public function count ()
	{
		$sql  = "select count(*) as total from {$this->table} {$this->where}";
		$data = $this->query ( $sql );

		return $data[ 0 ][ 'total' ];
	}

	/**
	 * 将对象转为数组
	 *
	 * @return array
	 */
	public function toArray ()
	{
		if ( isset( $this->data ) ) {
			return $this->data;
		}

		return [];
	}

	/**
	 * 组合where条件
	 *
	 * @param $where  条件语句
	 *
	 * @return $this
	 */
	public function where ( $where )
	{
		//将wher条件存储到where属性中
		$this->where = " where $where";

		return $this;
	}

	/**
	 * 获得主键
	 */
	private function getPk ()
	{
		$sql  = "desc " . $this->table;// desc article
		$data = $this->query ( $sql );//执行sql语句,调用自定义的query方法
		$pk   = '';
		foreach ( $data as $d ) {
			if ( $d[ 'Key' ] == 'PRI' ) {
				//说明该数据中的Field是主键
				$pk = $d[ 'Field' ];
				break;//终止循环
			}
		}

		return $pk;
	}

	/**
	 * 执行有结果集的查询
	 *
	 * @param $sql  查询的sql语句
	 *
	 * @return mixed  查询结果结
	 */
	public function query ( $sql )
	{
		try {
			$res = $this->pdo->query ( $sql );

			return $res->fetchAll ( PDO::FETCH_ASSOC );
		} catch ( PDOException $e ) {
			throw new Exception( "sql:{$sql} | " . $e->getMessage () );
		}
	}

	public function exec ( $sql )
	{
		try {
			$affectedRows = $this->pdo->exec ( $sql );
			if ( $lastInsertId = $this->pdo->lastInsertId () ) {
				//返回自增id
				return $lastInsertId;
			} else {//否则返回受影响的条数
				return $affectedRows;
			}
		} catch ( PDOException $e ) {
			throw new Exception( "sql:{$sql} | " . $e->getMessage () );
		}
	}
}

需要在system/model建立Article.php进行协助测试测试,Article.php名字不是固定的

<?php

namespace system\model;


use houdunwang\model\Model;

class Article extends Model
{
	
}

在Entry.php中进行测试,注意system中的类不会自动进行加载,需要修改composer.json配置项

"autoload":{
        "files":[
            "system/helper.php"
        ],
        "psr-4":{
            "houdunwang\\":"houdunwang",
            "app\\":"app\\",
            "system\\":"system\\"
        }
    }

然后执行

composer dump

###错误处理方法 composer的packagist(https://packagist.org/)搜索:`whoop`
选择第一个:filp/whoops
进入到项目根目录执行:

composer require filp/whoops

在houdunwang/core/Boot.php中加入

    $whoops = new \Whoops\Run;
   $whoops->pushHandler(new \Whoops\Handler\PrettyPageHandler);
   $whoops->register();

推送上到composer仓库之后即可以下载了

composer create-project chaorenwubin/frame c86frame dev-master --prefer-dist