CodeIgniter3 笔记
特点
优点
- 框架配置简单、执行效率高
- 有基本的路由功能,可以进行一定程度的路由配置
- 框架简单,且文档详细,上手成本低
缺点:
- 内部过于混乱,不易于扩展
- Model层只有简单的数据库操作封装
- CodeIgniter3不支持命名空间
- 没有模板引擎,(如果用来写API的话确实用不上)
开始
要求
- PHP 5.3.7+
- MySQL5.1+ 开启 mysqli 和 pdo
安装
- 没有
composer
安装方式(从4开始有),只能下载压缩包 - index.php文件位于根目录(默认),直接解析到public就行
- 为了安全性
system
和application
都可以放置在根目录之外,不会被浏览器直接访问。但需要设置在index.php
文件中对应的配置变量:$system_path
、$application_folder
和$view_folder
。 - 设置Apache的URL重写文件:
.htaccess
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?/$1 [L]
基础
框架目录
项目根目录
index.php 入口文件
.htaccess Apache 重写文件
├─application 项目目录
│ ├─cache 存放数据或模板的缓存文件
│ ├─config 配置文件目录
│ │ autoload.php 设置自动加载类库的配置文件
│ │ config.php 项目相关的配置文件
│ │ constants.php 常量配置文件
│ │ database.php 数据库配置文件
│ │ doctypes.php DOCTYPE标签预设
│ │ foreign_chars.php 外国字符转换配置文件
│ │ hooks.php 钩子配置文件
│ │ index.html 403文件 每个目录都有
│ │ memcached.php Memcached配置文件
│ │ migration.php 迁移类配置文件
│ │ mimes.php MIME类型配置文件
│ │ profiler.php
│ │ routes.php 路由配置文件
│ │ smileys.php 笑脸表情配置文件
│ │ user_agents.php 用户UA配置文件
│ │
│ ├─controllers 控制器
│ ├─core 项目核心程序
│ ├─helpers 项目辅助函数
│ ├─hooks 钩子,在不修改系统核心文件的基础上扩展系统功能
│ ├─language 语言包目录
│ ├─libraries 通用类库,可以自己写类库覆盖系统的类库
│ ├─logs 日志目录
│ ├─models 模型目录
│ ├─third_party 第三方库
│ └─views 视图目录
└─system 框架程序目录
├─core 框架核心程序
│ │ Benchmark.php 基准测试类
│ │ CodeIgniter.php 缓存驱动器
│ │ Common.php 加载基础类的公共函数
│ │ Config.php 配置类:CI_Config
│ │ Controller.php 控制器类:CI_Controller
│ │ Exceptions.php 排版类,格式化文本:CI_Exceptions
│ │ Hooks.php 钩子,核心文件扩展:CI_Hooks
│ │ index.html 403文件 防止暴露目录
│ │ Input.php 输入类:CI_Input
│ │ Lang.php 语言类:CI_Lang
│ │ Loader.php 加载器类:CI_Loader
│ │ Log.php 日志类:CI_Log
│ │ Model.php 模型类:CI_Model
│ │ Output.php 输出类:CI_Output
│ │ Router.php 路由类:CI_Router
│ │ Security.php 安全类,XSS过滤CSRF过滤:CI_Security
│ │ URI.php URL类:CI_URI
│ │ Utf8.php
├─database 数据库相关操作程序
├─fonts 字库
├─helpers 辅助函数
├─language 语言包目录
└─libraries 通用类库
URL和路由
- 遵循
http://域名/控制器/方法
- 例如:
http://localhost/user/add
则表示用户模块下的添加用户方法 - 如果域名中包含
index.php
,可以通过URL重写去掉 - 支持使用路由对URL进行美化,可以使用正则表达式或回调函数
保留路由
在application\config\routes.php
文件中可以配置:
$route['default_controller']
默认加载那个控制器,默认是Welcome
$route['404_override']
当访问控制器不存在时加载该控制器,若不设置 则加载application/views/errors/error_404.php
文件$route['translate_uri_dashes']
是否将url中的-
自动转换为_
编码规范
- PHP结束标签
- 所有的结束标签不使用
?>
,用一个空行代替
- 所有的结束标签不使用
文件命名
- 类文件命名是用大写字母开头
- 配置文件、视图文件、脚本文件使用全小写
- 可以使用下划线分割单词 ``` 错误的: somelibrary.php someLibrary.php SOMELIBRARY.php Some_Library.php
Application_config.php Application_Config.php applicationConfig.php
正确的: Somelibrary.php Some_library.php
applicationconfig.php application_config.php ```
类和方法命名
- 类名必须使用大写开头,多个单词之间使用下划线分割,不要使用驼峰命名法 ``` 错误的: class superclass class SuperClass
正确的: class Super_class
- 类名全部使用小写,并且应该明确指出该方法的功能,最好包含一个动词。冗长的名称使用下划线分割多个单词
错误的: function fileProperties() // not descriptive and uses CamelCase function getfileproperties() // Better! But still missing underscore separator function getFileProperties() // uses CamelCase function get_the_file_properties_from_the_file() // wordy
正确的: function get_file_properties() // descriptive, underscore separator, and all lowercase letters
- 私有方法和变量应该使用下划线开头
- 变量命名
- 使用全小写,下划线分割,并且需要明确指出该变量的使用用途
- 非常短无意义的变量只能在for循环或迭代器中使用
- 常量命名
- 常量命名规则与变量一致,但需要全部大写
- 尽量使用CodeIgniter定义好的常量:`SLASH`、`LD`、`RD`、`PATH_CACHE`等
- TRUE、FALSE和NULL
- TRUE,FALSE和NULL关键字全部使用大写
- 代码缩进
- 缩进使用TAB而不是空格
- 除了类的定义外,所有的大括号需要独占一行
- 中括号和小括号不要有多余的空格
- 注释
- 单行注释与代码是在一起的
- 多行注释需要与代码中间有一个空格
- 使用DocBlock风格的注释,可以被IDE识别
/**
- Super Class *
- @package Package Name
- @subpackage Subpackage
- @category Category
- @author Author Name
@link http://example.com */ class Super_class {
/**
- Encodes string for use in XML *
- @param string $str Input string
- @return string */ function xml_encode($str)
/**
- Data for class manipulation *
- @var array */ public $data = array(); ```
- SQL查询
- SQL的关键字永远大写:SELECT、INSERT、UPDATE、WHERE、AS、JOIN、ON、IN等
- 如果查询过长,建议分成多行,最好是一行只有一个从句
自动加载
CodeIgniter 的自动加载特性允许每次运行时自动初始化类库、辅助函数和模型等
支持自动加载到有下面这些:
- libraries/ 目录下的核心类
- helpers/ 目录下的辅助函数
- config/ 目录下的用户自定义配置文件
- system/language/ 目录下的语言文件
- models/ 目录下的模型类
若需要CodeIgniter 支持Compooser的自动加载,只需要在配置文件application/config/config.php
文件中的 $config['composer_autoload']
设置为 TRUE
或者设置为你自定义的路径。
控制器 Controller
控制器就是application/controllers/
目录下的类文件。
比如访问:[http://example.com/blog/index](http://example.com/blog/index)
,就会加载控制器目录下的Blog.php
文件中的index
方法
<?php
// 需要继承父控制器类,才可以使用父类方法
class Blog extends CI_Controller {
public function index()
{
echo 'Hello World!';
}
}
URL传参
访问域名:http://codeigniter/demo/msg/23/zhangsan
接收参数代码:
<?php
class Demo extends CI_Controller {
public function msg($id,$name){
echo '用户id:'.$id.PHP_EOL;
echo '用户名称:'.$name;
}
}
输出内容:用户id:23 用户名称:zhangsan
接收数据
CodeIgniter提供了几个辅助方法来分别获取POST、GET、COOKIE、SERVER数组中的数据。CI框架做了一些安全性的过滤,比直接使用$_POST
,$_get
更安全,同时会检查数据是否存在,如果不存在则返回NULL。
主要有以下几个方法:
$thins->input->post()
$this->input->get()
$thins->input->cookie()
$thins->input->server()
接收php://input流
如果需要使用PUT、DELETE、PATCH或其他的请求方法,只能使用特殊的流来读取,CodeIgniter对这个流进行了封装,使用$this->input->raw_input_stream;
属性就能读取,如果输入流也是数组形式,则可以通过input_stream()
方法来进行读取,与get和post一样,如果请求的数据不存在,则会返回NULL。
同样支持XSS过滤:
this->input->input_stream('key', TRUE); // XSS Clean
$this->input->input_stream('key', FALSE); // No XSS filter
重映射方法
如果在控制器中写一个_remap()
方法,不管访问的具体是哪个方法,都会进入到_remap()
方法,然后由_remap()
重写路由,可以接受一个参数,决定加载那个方法。
<?php
public function _remap($method)
{
if ($method === 'some_method')
{
$this->$method();
}
else
{
$this->default_method();
}
}
构造函数
如果需要在控制器中使用构造函数,则必须在构造函数中调用父类的构造函数,因为子类的构造函数会覆盖掉父类的构造函数。
<?php
class Blog extends CI_Controller {
public function __construct()
{
parent::__construct();
}
}
数据库 Database
连接数据库
默认数据库类是不进行自动加载的,如果需要自动加载,可在 application/config/autoload.php
中的 library 数组里添加 database:
$autoload['libraries'] = array('database');
也可以使用手动方式加载数据库配置并初始化数据库类,如果想在整个类中使用,需要把初始化代码写在构造函数中:
$this->load->database();
database()
方法支持在初始化的时候传递一些参数:
- 数据库连接值,使用数组或者DSN字符串传递
- 布尔值,是否返回连接对象(连接多个数据库时会用到)
- 布尔值,是否启用查询构造器类,默认为TRUE
从配置文件中选择一个特定分组:
$this->load->database('分组名');
连接一个完全手动指定的数据库,可以传递一个数组参数:
$config['hostname'] = 'localhost';
$config['username'] = 'myusername';
$config['password'] = 'mypassword';
$config['database'] = 'mydatabase';
$config['dbdriver'] = 'mysqli';
$config['dbprefix'] = '';
$config['pconnect'] = FALSE;
$config['db_debug'] = TRUE;
$config['cache_on'] = FALSE;
$config['cachedir'] = '';
$config['char_set'] = 'utf8';
$config['dbcollat'] = 'utf8_general_ci';
$this->load->database($config);
使用DSN作为参数连接数据库:
$dsn = 'dbdriver://username:password@hostname/database';
$this->load->database($dsn);
如果需要连接多个数据库,可以使用这种方式:
$DB1 = $this->load->database('group_one', TRUE);
$DB2 = $this->load->database('group_two', TRUE);
重新连接
当要处理耗时较长的PHP操作时,如果超过了数据库最长连接时间,可以使用reconnect()
向数据库发起一次ping命令,重新建立连接
$this->db->reconnect();
关闭数据库链接
CodeIgniter 可以智能的管理或关闭数据库链接,但除此之外,还可以使用下面的方式手动关闭:
$this->db->close()
数据库配置
CodeIgniter 有一个专门的配置文件用来保存数据库配置:application/config/database.php
,配置文件中存放一个多维数组:$db
$db['default'] = array(
'dsn' => '',
'hostname' => 'localhost',
'username' => 'root',
'password' => '',
'database' => 'database_name',
'dbdriver' => 'mysqli',
'dbprefix' => '',
'pconnect' => TRUE,
'db_debug' => TRUE,
'cache_on' => FALSE,
'cachedir' => '',
'char_set' => 'utf8',
'dbcollat' => 'utf8_general_ci',
'swap_pre' => '',
'encrypt' => FALSE,
'compress' => FALSE,
'stricton' => FALSE,
'failover' => array()
);
或者直接使用DSN:
// PDO
$db['default']['dsn'] = 'pgsql:host=localhost;port=5432;dbname=database_name';
可以设置多个组,来满足开发、测试、生产环境的需要,例如设置一个 “test” 组,可以这样:
$db['test'] = array(
'dsn' => '',
'hostname' => 'localhost',
'username' => 'root',
'password' => '',
'database' => 'database_name',
'dbdriver' => 'mysqli',
'dbprefix' => '',
'pconnect' => TRUE,
'db_debug' => TRUE,
'cache_on' => FALSE,
'cachedir' => '',
'char_set' => 'utf8',
'dbcollat' => 'utf8_general_ci',
'swap_pre' => '',
'compress' => FALSE,
'encrypt' => FALSE,
'stricton' => FALSE,
'failover' => array()
);
然后设置配置文件中的 $active_group
变量,告诉系统默认使用哪个组链接
构造查询器
可以通过配置文件中的 $query_builder
变量对 “查询构造器类”继续全局设定 ,如果不使用可以通过设置为false来减少资源消耗。
参数解释
这里只是常用的参数解释,完整的请看官方文档:
配置名 | 描述 |
---|---|
dsn | DSN连接字符串 |
hostname | 数据库的主机名 |
username | 数据库用户名 |
password | 数据库密码 |
database | 链接的数据库名 |
dbdriver | 数据库类型:mysq、postgres、odbc等,必须为小写 |
dbprefix | 表前缀 |
pconnect | 布尔值,是否持续链接 |
db_debug | 布尔值,是否显示数据库错误信息 |
cache_on | 布尔值,是否开启数据库查询缓存 |
cachedir | 数据库查询缓存存储目录,服务器绝对路径 |
char_set | 与数据库通信的字符集 |
dbcollat | 与数据库通信时所使用的字符规则,仅限mysql和mysqli驱动 |
compress | 布尔值,是否使用客户端压缩协议,仅限MySQL |
port | 数据库端口号,要使用这个值,应该添加一行代码到数据库配置组 |
SQLite
使用SQLite时,无需指定用户名和密码,数据库名直接设置数据库文件的路径即可。
查询数据库
常规查询
要提交一个查询,使用query函数:
$this->db->query('SELECT * FROM user');
- 当执行读类型的查询时,将会返回一个对象形式的结果集。
- 当执行写类型的查询时,将会简单的返回布尔值来表示操作是否成功
转义查询
在提交数据时可以通过CodeIgniter 的三个方法来进行转义:
$this->db->escape()
会检测数据类型,仅转义字符串类型的数据$this->db->secape_str()
忽略数据类型,对传入的数据进行转义,这个方法用的不多$this->db->escape_like_str()
用于处理LIKE语句中的字符串
查询绑定
查询绑定可以简化查询语法:
$sql = "SELECT * FROM some_table WHERE id = ? AND status = ? AND author = ?";
$this->db->query($sql, array(3, 'live', 'Rick'));
也可以使用二维数组,会被转换为IN语句的集合:
$sql = "SELECT * FROM some_table WHERE id IN ? AND status = ? AND author = ?";
$this->db->query($sql, array(array(3, 6), 'live', 'Rick'));
查询绑定所有的值都会被转义,生成安全的查询语句,不写用手工进行转义
错误处理
获取最近一次发生的错误,使用error()
方法可以得到一个包含错误代码和错误消息的数组:
if ( ! $this->db->simple_query('SELECT `example_field` FROM `example_table`'))
{
$error = $this->db->error(); // Has keys 'code' and 'message'
}
生成查询结果
结果数组
result() 别名:result_object()
这个方法会以对象数组的形式返回查询结果,如果查询失败返回空数组,可以在foreach循环中使用它
$query = $this->db->query("SELECT * FROM user");
foreach ($query->result() as $row)
{
echo $row->age;
echo $row->name;
echo $row->sex;
}
result_array()方法
这个方法会返回一个数组形式的查询结果,如果无结果,则返回一个空数组。
$query = $this->db->query("SELECT * FROM user");
foreach ($query->result_array() as $row)
{
echo $row['age'];
echo $row['name'];
echo $row['sex'];
}
结果行
row()
这个方法返回单独的一行结果,如果查询结果不止一行,则返回的第一行,返回的是对象形式:
$query = $this->db->query("YOUR QUERY");
$row = $query->row();
if (isset($row))
{
echo $row->title;
echo $row->name;
echo $row->body;
}
如果需要发返回特定行号,可以把行号作为第一个参数传递:
$row = $query->row(5);
row_arrray() 这个方法和上面的方法完全一样,只是返回的数组而不是对象
另外可以使用下面的方法从结果集中获取数据,默认返回对象,若传递参数”array”字符串,则返回数组:
方法 | 含义 |
---|---|
$query->first_row() |
获取第一行 |
$query->last_row() |
获取最后一行 |
$query->next_row() |
获取下一行 |
$query->previous_row() |
获取上一行 |
unbuffered_row()
和row()
方法一样,但不会把所有结果预加载到内存中,如果查询结果集不止一行,则会返回当前一行,并将指针指向下一行:
$query = $this->db->query("YOUR QUERY");
while ($row = $query->unbuffered_row())
{
echo $row->title;
echo $row->name;
echo $row->body;
}
可以制定不同的返回类型:
$query->unbuffered_row(); // object 对象
$query->unbuffered_row('object'); // object 对象
$query->unbuffered_row('array'); // array 数组
num_rows()
用于返回查询结果的行数
<?php
$query = $this->db->query('SELECT * FROM my_table');
echo $query->num_rows();
num_fields()
返回查询结果集的字段数
<?php
$query = $this->db->query('SELECT * FROM my_table');
echo $query->num_fields();
fiee_result()
释放掉查询结果集所占用的内存,并删除结果集的资源标识。
辅助函数
执行查询的信息
获取 INSTER 后 通过此方法获取新插入的ID
$this->db->insert_id();
获取 INSERT 、UPDATE 等写类型语句,影响行数
$this->db->affected_rows();
获取上一次执行的查询语句
$this->db->last_query();
获取查询构造器组装 SELECT 语句,返回 SQL 和查询结果集。
$this->db->get();
获取查询构造器组装 SELECT 语句,此语句只返回SQL,不执行查询。
$this->db->get_compiled_select();
数据库信息
获取表的总行数 第一个参数为表名:
$this->db->count_all('table_name');
钩子 Hooks
个人理解就类似于生命周期函数,在配置文件 config/hooks.php
设置什么时候调用那个文件的哪个方法,和ThinkPHP中的行为是一样的。
定义Hooks
首先需要在文件 application/config/config.php
文件中全局开启钩子:
<?php
$config['enable_hooks'] = TRUE;
然后再钩子的配置文件application/config/hooks.php
中定义钩子的数组:
<?php
$hook['挂载点名称']=[
// 需要调用的类,如果直接写方法不写类可以为空
'class' => 'Demo',
// 需要调用的方法或函数名
'function' => 'test',
// 调用钩子的文件名
'filename' => 'Demo.php',
// 调用钩子所处的目录
'filepath' => 'hooks',
// 传递的参数,可选
'params' => 'pre_system'
];
如果需要挂载多个钩子到同一个挂载点,直接写成二维数组即可:
<?php
$hook['挂载点名称'][]=[...];
$hook['挂载点名称'][]=[...];
挂载点
pre_system
系统执行的早期调用,只加载了基准测试类和钩子类pre_controller
在控制器调用之前触发,所有的基础类已加载post_controller_constructor
在控制器实例化之后执行,还没有调用任何方法post_controller
在控制器完全运行结束时执行display_override
在最终输出内容时调用,会覆盖_display()
方法,需要手动输出cache_override
用自己的方法替换输出类中的_display_cache()
方法,可以自己控制缓存显示机制post_system
在最终页面发送给浏览器之后,框架的最后期会调用Hooks 代码示例
以上面的配置文件为例,在application/hooks
目录创建Demo.php
文件:<?php class Demo{ function test($name){ echo 'Hooks被调用了:'.$name; } }
自定义Hook
可以在配置文件中自定义挂载点名称:
$hook['test']=[
'class' => 'Demo',
'function' => 'test',
'filename' => 'Demo.php',
'filepath' => 'hooks',
'params' => '我是测试的hook'
];
然后再想要触发的地方使用:
$this->hooks->call_hook('test');
返回值:调用成功返回true
,调用失败返回false
,钩子不能使用return
返回数据