lnmp 开启php错误打印

php –ini
Configuration File (php.ini) Path: /usr/local/php/etc
Loaded Configuration File: /usr/local/php/etc/php.ini
Scan for additional .ini files in: /usr/local/php/conf.d
Additional .ini files parsed: (none)

vi /usr/local/php/etc/php.ini

在文件中查找 ‘display_errors’   查找到 display_errors = Off 或者 display_errors = On, Off为关闭错误提示,On为打开错误提示,根据需求修改即可。

也可在php文件中加入以下代码

 

//禁用错误报告
error_reporting(0);
//报告运行时错误
error_reporting(E_ERROR | E_WARNING | E_PARSE);
//报告所有错误
error_reporting(E_ALL);

 

windows中使用git-bash,新增快捷命令php7 php 环境变量

windows上环境变量中的php配置的php5.3.6,但是想要在windows上的git-bash 使用php7。

1 使用git-bash,使用vi打开文件aliases.sh:


ttwp@ttwp MINGW64 /c/xampp/htdocs/laravel-git (5.3)

$ vi /etc/profile.d/aliases.sh

2 在该文件中新增一条代码:


alias php7='C:/xampp/php7/php-7.3.3-Win32-VC15-x64/php'

单引号中间的是你的php7的安装路径。

3 将git-bash关闭后,重新打开,输入php7 -v:


ttwp@ttwp MINGW64 /c/xampp/htdocs/laravel-git (5.3)

$ php7 -v

PHP 7.3.3 (cli) (built: Mar  6 2019 21:53:23) ( ZTS MSVC15 (Visual C++ 2017) x64 )

Copyright (c) 1997-2018 The PHP Group

Zend Engine v3.3.3, Copyright (c) 1998-2018 Zend Technologies

ttwp@ttwp MINGW64 /c/xampp/htdocs/laravel-git (5.3)

$ php -v

PHP 5.6.32 (cli) (built: Oct 25 2017 16:02:15)

Copyright (c) 1997-2016 The PHP Group

Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies

php 图形用户界面GUI 开发

一、下载指定系统扩展

1
2
http://pecl.php.net/package/ui
http://pecl.php.net/package/ui/2.0.0/windows

由于我的系统是64位win10,php版本是7.1,所以选择7.1 Thread Safe (TS) x64,linux用户可以自行下载源码包,编译安装。

解压php_ui-2.0.0-7.1-ts-vc14-x64.zip,把php_ui.dll复制到你php.ini中extension_dir设置的目录,把libui.dll和pthreadVC2.dll复制到C:\Windows\System32目录下。

在php.ini中加入如下:

1
extension=php_ui.dll

然后重启服务,phpinfo()查看,ui扩展安装成功。

 

二、我们创建一个简单的计算器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<?php
use UI\Window;
use UI\Size;
use UI\Controls\Entry;
use UI\Controls\Label;
use UI\Controls\Button;
use UI\Controls\Grid;
//创建一个窗口
//参数一表示窗口标题
//参数二表示窗口大小
//参数三表示是否显示菜单
$win new Window('简单的计算器'new Size(640, 480), true);
//创建一个文本框
//Entry::Normal 普通单行文本框
//Entry::Password 密码框
//Entry::Search 搜索框
$num1 new Entry(Entry::Normal);
$num2 new Entry(Entry::Normal);
$ret new Entry(Entry::Normal);
//创建一个标签
$lab new Label('+');
//创建一个按钮
$btn new class('计算'extends Button {
    public function __construct($text) {
        parent::__construct($text);
    }
    protected function onClick() {
        global $num1$num2$ret;
        $n1 $num1->getText();
        $n2 $num2->getText();
        $ret->setText($n1 $n2);
    }
};
//创建一个网格
$grid new Grid();
//把上面的控件加入到网格布局中
$grid->append($num1, 0, 0, 1, 1, true, Grid::Center, false, Grid::Center);
$grid->append($lab, 0, 1, 1, 1, true, Grid::Center, false, Grid::Center);
$grid->append($num2, 0, 2, 1, 1, true, Grid::Center, false, Grid::Center);
$grid->append($btn, 0, 3, 1, 1, true, Grid::Center, false, Grid::Center);
$grid->append($ret, 0, 4, 1, 1, true, Grid::Center, false, Grid::Center);
//把布局加入到窗口中
$win->add($grid);
//显示窗口
$win->show();
UI\run();

在控制台下运行php脚本

1
> php index.php

运行结果如下:

 

三、我们创建一个常用的注册表单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
<?php
use UI\Window;
use UI\Size;
use UI\Controls\Box;
use UI\Controls\Entry;
use UI\Controls\Button;
use UI\Controls\Form;
use UI\Controls\Radio;
use UI\Controls\Check;
use UI\Controls\Combo;
use UI\Controls\MultilineEntry;
//创建一个窗口
//参数一表示窗口标题
//参数二表示窗口大小
//参数三表示是否显示菜单
$win new Window('简单的计算器'new Size(640, 480), true);
//创建一个表单
$frm new Form();
//用户名
$user new Entry(Entry::Normal);
$frm->append('用户名:'$user, false);
//密码
$pwd new Entry(Entry::Password);
$frm->append('密码:'$pwd, false);
//性别(单选)
$sex new Radio();
$sex->append("男");
$sex->append("女");
$sex->append("未知");
$frm->append('性别:'$sex, false);
//爱好(多选)
//创建一个盒子,水平排列
$loveBox new Box(Box::Horizontal);
$love1 new Check('看书');
$love2 new Check('旅游');
$love3 new Check('游戏');
//把多选控件加入盒子中
$loveBox->append($love1);
$loveBox->append($love2);
$loveBox->append($love3);
$frm->append('爱好:'$loveBox, false);
//地区(下拉框)
$area new Combo();
$area->append("北京");
$area->append("上海");
$area->append("武汉");
$frm->append('地区:'$area, false);
//简介(多行文本)
$desc new MultilineEntry();
$frm->append('简介:'$desc, false);
//注册按钮
$reg new class('注册'$winextends Button {
    protected $win;
    public function __construct($text$win) {
        $this->win = $win;
        parent::__construct($text);
    }
    //用于重写父类的单击事件
    protected function onClick() {
        $this->win->msg('消息''你点击了注册按钮');
    }
};
$frm->append(''$reg);
$win->add($frm);
//显示窗口
$win->show();
UI\run();

运行结果如下:

为了避免每次都要打命令运行php脚本,我们可以写个bat脚本来运行。

1
2
D:\amp\php7\php.exe -f D:\wwwroot\demo1\index.php
pause

注意php.exe的路径和运行脚本路径,保存为run.bat,运行结果如下:

Ajax跨域请求,无法传递及接收cookie信息解决方案 (开发背景:实现跨域登录)

//php脚本增加
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST');
header('Access-Control-Max-Age: 1000');
header('Access-Control-Allow-Credentials: true');
/*js设置登录状态*/
$.ajax({
    url:"https://goonls.com/sign-in.php",
    cache:false,
    data:{user:$('#user_email').val(),password:$('#exampleInputPassword1').val()},
    method:"POST",
    dataType:'json',
    xhrFields:{//这里是重点
        withCredentials:true
    },
    success:function (data) {

    },
    error:function (e) {

    }
});

参考地址

https://www.cnblogs.com/yalong/p/9067525.html

HTML5 Access-Control-Allow-Origin解决跨域问题

mysql根据经纬度获取附近的商家

创建geo表

create table geo(
    geo_id INT NOT NULL AUTO_INCREMENT,
    lng float NOT NULL,
    lat float NOT NULL,
    name VARCHAR(100) NULL,
    PRIMARY KEY ( geo_id )
);
INSERT INTO `geo`(`lng`, `lat`, `name`) VALUES (118.302416,33.958887,"实验小学");
INSERT INTO `geo`(`lng`, `lat`, `name`) VALUES (118.303997,33.95188,"宿迁市人民医院");
INSERT INTO `geo`(`lng`, `lat`, `name`) VALUES (118.302991,33.935828,"宿迁学院");
INSERT INTO `geo`(`lng`, `lat`, `name`) VALUES (118.28215,33.959307,"金陵名府");
INSERT INTO `geo`(`lng`, `lat`, `name`) VALUES (118.290081,33.925404,"润园");
INSERT INTO `geo`(`lng`, `lat`, `name`) VALUES (118.354751,33.959007,"国际馆");

下面是google给的解决方案(基于公里km)。

SELECT  
  geo_id, `name`,(  
    6371 * acos (  
      cos ( radians(33.958887) )  
      * cos( radians( lat ) )  
      * cos( radians( lng ) - radians(118.302416) )  
      + sin ( radians(33.958887) )  
      * sin( radians( lat ) )  
    )  
  ) AS distance  
FROM geo
HAVING distance < 20  
ORDER BY distance 
LIMIT 0 , 20

其中33.958887是纬度,118.302416是经度。

牛了个逼的。

/** 附近的商家 */
public function get_near_business() {
        if (!$this->validate->validate('lng', ['require','regex|-?((0|1?[0-7]?[0-9]?)(([.][0-9]{1,4})?)|180(([.][0]{1,4})?))'])) { // 经度
            $this->json->setErr(10001, '缺少lng或lng格式不正确');
            $this->json->Send();
        }
        if (!$this->validate->validate('lat', ['require','regex|-?((0|[1-8]?[0-9]?)(([.][0-9]{1,4})?)|90(([.][0]{1,4})?))'])) { // 纬度
            $this->json->setErr(10001, '缺少lat或lng格式不正确');
            $this->json->Send();
        }

        if (!isset($_POST['page']) || $_POST['page'] < 1) {
            $_POST['page'] = 1;
        }
        // 分页获取附近的商家信息
        $sql_count = "SELECT  id, `name`,( 6371 * acos (  
                    cos ( radians(".$_POST['lat'].") )  
                    * cos( radians( lat ) )  
                    * cos( radians( lng ) - radians(".$_POST['lng'].") )  
                    + sin ( radians(".$_POST['lat'].") )  
                    * sin( radians( lat ) )  
                    )  
                ) AS distance  
                FROM tf_my_business
                WHERE `status` = 1
                HAVING distance < 10";
        $count = count(M()->query($sql_count));
        $hasPage = ceil($count / C('PAGE.LIMIT'));
        $hasPage = $hasPage ? $hasPage : 1;

        if ($_POST['page'] > $hasPage) {
            $this->json->setErr(10002, '页数有误');
            $this->json->Send();
        }

        $limit = (($_POST['page'] - 1) * C('PAGE.LIMIT')) . "," .C('PAGE.LIMIT');
        $sql_list = "SELECT  `id`,`name`,`info`,( 6371 * acos (  
                    cos ( radians(".$_POST['lat'].") )  
                    * cos( radians( lat ) )  
                    * cos( radians( lng ) - radians(".$_POST['lng'].") )  
                    + sin ( radians(".$_POST['lat'].") )  
                    * sin( radians( lat ) )  
                    )  
                ) AS distance  
                FROM tf_my_business
                WHERE `status` = 1
                HAVING distance < 10 
                ORDER BY distance ASC 
                LIMIT ".$limit;
        $datalist = M()->query($sql_list);
        if ($datalist) {
            // 处理datalist
            $my_business_img_model = M('my_business_img');
            foreach ($datalist as &$v) {
                // 获取主图
                $my_business_img_info = $my_business_img_model->where(['m_b_id'=>$v['id'],'type'=>1,'is_main'=>1])->find();
                $v['img'] = $my_business_img_info['img'];
                if (strpos($v['img'],'cdn') === false) {
                    $v['img'] = C('CDN.URI').$v['img'];
                }
            }

            $data['datalist'] = $datalist;
            $data['current_page'] = $_POST['page'];
            $data['hasPage'] = $hasPage;
            $this->json->setErr(0, '获取成功');
            $this->json->setAttr('data',$data);
            $this->json->Send();
        } else {
            $this->json->setErr(10003, '暂无数据');
            $this->json->Send();
        }
}
{
    "errno": 0,
    "errdesc": "获取成功",
    "timestamp": 1524749336,
    "data": {
        "datalist": [
            {
                "id": "3",
                "name": "京东",
                "info": "京东",
                "distance": "4.665364145881758",
                "img": "https://cdn.caomall.net/1524732806744365022.png"
            }
        ],
        "current_page": "1",
        "hasPage": 1
    }
}

 

https://www.cnblogs.com/jiqing9006/p/8954831.html

 

php获取html内的纯文本

在写xml的时候,文档要求内容里面只要图片和段落就可以了,其他的css,js什么的都不需要。

所以,在输出的时候,就要用正则去过滤掉不需要的标签代码。

第一种:php正则去除js标签代码。

$preg = "/<script[\s\S]*?<\/script>/i";
$content = preg_replace($preg, "", $content);

第二种:php正则去除meta标签

$preg = "/<meta[\s\S]*?>/i";
$content = preg_replace($preg, "", $content);

第三种:php正则去除link标签

$preg = "/<link[\s\S]*?>/i";
$content = preg_replace($preg, "", $content);

第四种:php正则去除页内css样式

$preg = "/<style[\s\S]*?<\/style>/i";
$content = preg_replace($preg, "", $content);

第五种:php正则去除行内样式,id,class等

$preg = "/(style|id|class)=\"[\s\S]*?\"/i";
$content = preg_replace($preg, "", $content);

其他的标签可以自行脑补。

 

 

[php]
<pre>function getClearStr($str){
//去掉中,英文标点符号和HTML代码
$str = preg_replace( "/<style[\s\S]*?<\/style>/i", "", $str );
$str = preg_replace( "/<script[\s\S]*?<\/script>/i", "", $str );
$str=preg_replace(‘/\s/’,”,preg_replace("/[[:punct:]]/",”,strip_tags(html_entity_decode($str,ENT_QUOTES,’UTF-8′))));

return $str;
}</pre>
[/php]

令人困惑的strtotime

经常会有人被strtotime结合-1 month, +1 month, next month的时候搞得很困惑, 然后就会觉得这个函数有点不那么靠谱, 动不动就出问题. 用的时候就会很慌…

这不, 刚刚就有人在微博上又问我:

鸟哥,今天是2018-07-31 执行代码:

  1. date(“Y-m-d”,strtotime(“-1 month”))

怎么输出是2018-07-01?

好的吧, 虽然这个问题看起来很迷惑, 但从内部逻辑上来说呢, 其实是”对”的, 你先别着急哈, 让我慢慢讲:

我们来模拟下date内部的对于这种事情的处理逻辑:

  • 1. 先做-1 month, 那么当前是07-31, 减去一以后就是06-31.
  • 2. 再做日期规范化, 因为6月没有31号, 所以就好像2点60等于3点一样, 6月31就等于了7月1

是不是逻辑很”清晰”呢? 我们也可以手动验证第二个步骤, 比如:

  1. var_dump(date(“Y-m-d”, strtotime(“2017-06-31”)));
  2. //输出2017-07-01

也就是说, 只要涉及到大小月的最后一天, 都可能会有这个迷惑, 我们也可以很轻松的验证类似的其他月份, 印证这个结论:

  1. var_dump(date(“Y-m-d”, strtotime(“-1 month”, strtotime(“2017-03-31”))));
  2. //输出2017-03-03
  3. var_dump(date(“Y-m-d”, strtotime(“+1 month”, strtotime(“2017-08-31”))));
  4. //输出2017-10-01
  5. var_dump(date(“Y-m-d”, strtotime(“next month”, strtotime(“2017-01-31”))));
  6. //输出2017-03-03
  7. var_dump(date(“Y-m-d”, strtotime(“last month”, strtotime(“2017-03-31”))));
  8. //输出2017-03-03

那怎么办呢?

从PHP5.3开始呢, date新增了一系列修正短语, 来明确这个问题, 那就是”first day of” 和 “last day of”, 也就是你可以限定好不要让date自动”规范化”:

  1. var_dump(date(“Y-m-d”, strtotime(“last day of -1 month”, strtotime(“2017-03-31”))));
  2. //输出2017-02-28
  3. var_dump(date(“Y-m-d”, strtotime(“first day of +1 month”, strtotime(“2017-08-31”))));
  4. ////输出2017-09-01
  5. var_dump(date(“Y-m-d”, strtotime(“first day of next month”, strtotime(“2017-01-31”))));
  6. ////输出2017-02-01
  7. var_dump(date(“Y-m-d”, strtotime(“last day of last month”, strtotime(“2017-03-31”))));
  8. ////输出2017-02-28

那如果是5.3之前的版本(还有人用么?), 你可以使用mktime之类的, 把所有的日子忽略掉, 比如都限定为每月1号就可以了, 只不过就不如直接用first day来的更加优雅.

现在, 搞清楚了内部原理, 是不是就不慌了? 🙂

PHP Session锁及并发机制 | void session_write_close(void)函数

手册中有这样的描述:
void session_write_close ( void )

End the current session and store session data.

Session data is usually stored after your script terminated without the need to call session_write_close(), but as session data is locked to prevent concurrent writes only one script may operate on a session at any time. When using framesets together with sessions you will experience the frames loading one by one due to this locking. You can reduce the time needed to load all the frames by ending the session as soon as all changes to session variables are done.

也就是说session是有锁的,为防止并发的写会话数据,php自带的的文件保存会话数据是加了一个互斥锁(在session_start()的时候)。
程序执行session_start(),此时当前程序就开始持有锁。
程序结束,此时程序自动释放Session的锁。

如果同一个客户端同时并发发送多个请求(如ajax在页面同时发送多个请求),且脚本执行时间较长,就会导致session文件阻塞,影响性能。因为对于每个请求,PHP执行session_start(),就会取得文件独占锁,只有在该请求处理结束后,才会释放独占锁。这样,同时多个请求就会引起阻塞。解决方案如下:
修改会话变量后,立即使用session_write_close()来保存会话数据并释放文件锁。

session_start();   
$_SESSION['test'] = 'test';
session_write_close();
......
//do something

php 获取当前浏览器语言 EN CN

/*获取客户端语言设置到session*/
public function clientLang()
{
    $languageValue = Yii::$app->session->get('language');
    if (!isset($languageValue))
    {
        //只取前4位,这样只判断最优先的语言。如果取前5位,可能出现en,zh的情况,影响判断。
        $lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 4);
        if (preg_match("/zh-c/i", $lang)||preg_match("/zh/i", $lang))
            Yii::$app->session['language'] ='CN';
        else
            Yii::$app->session['language'] ='EN';
    }


}

Composer实现PHP中类的自动加载

本篇博客承接上一篇,学习一下Composer实现的PHP的类的自动加载方式。首先说明一下,Composer是PHP针对PHP语言的第三方的依赖管理工具,将工程所用到的依赖文件包含在composer.json文件中,使用composer install命令就可以将所使用对应库或者文件加载进工程里面。下面分两部分介绍composer的基础,分别是composer的依赖管理和自动加载。

依赖管理

在composer出现之前,如果咋PHP项目中需要第三方的依赖文件,则需要程序员将所需要的源代码拷贝进工程中或者将源代码对应的文件下载下来手动添加到工程中。如果所需要的依赖文件依赖于更多的第三方文件,则程序员会陷入拷贝依赖文件的黑洞中,费时费力不说,有可能还会出现一些失误,composer就是在这种情况下出现的用于减轻程序员的对于依赖管理的负担的工具。

Composer通过使用配置文件composer.json文件完成依赖管理。composer.json文件包含了项目的简单介绍、项目对于外界的库或文件的依赖。从composer.json的扩展名就可以看得出来,composer.json中的内容是按照json标准组织的。本篇博客集中在类的自动加载机制上,因此对于composer.json中关于项目的作者等相关信息的解释忽略不解释。

在composer中将本项目所需要的外部依赖包写在关键字require对应的值中,require键可以对应着多个所需要的包,各个不同的包之间用逗号分隔。假设项目需要一个外部依赖包monolog,下面是在compose.json文件中对于monolog包的依赖配置项:

1
2
3
4
5
{
    "require":{
        "monolog/monolog": "1.0.* @dev"
    }
}

如上所示,require关键字将会映射包的名称monolog和包的版本1.0.*。其中,包的名称有两部分组成,中间以“/”分隔,“/”之前代表的包的所有者,在Github上一般是代表的Github的用户名,“/”代表的是实际的包的名称。其中“/”之前的名称必须是唯一的,但是”/”之后的包的名称是可以存在重复的,例如“Jack/monolog”和“monolog/monolog”是可以共存的。而后面的”1.0.*”代表的是所依赖的包的版本,其中“*”代表的是“1.0”之下的任意一个版本,例如:1.0.1,1.0.2或者1.0.9等等。“@dev”代表了可以获取该包的开发版本。默认情况下,composer将获取所需要的包的最新的稳定版本,而不会考虑开发版本,因为开发版本一般是不太稳定的版本。但是,如果确定开发版本没有什么问题就可以加上“@dev”以允许获取开发的版本。如果没有加上“@dev”,而除了开发版本之外不存在别的版本的话,则composer加载依赖项出错。

在composer中配置好依赖的第三方的包之后,就可以使用composer install命令获取第三方的包了。运行成功之后就可以项目中就会出现vendor文件夹,vendor文件夹中会包含我们在require中所列出的monolog文件。

出了生成列在composer.json中关键字require值下的文件之外,成功运行composer install之后还会生成对应的composer.lock文件,该文件依据composer.json中的依赖项生成依赖包对应的版本。这里需要说明的是,在我们运行composer install的时候会首先判断是否存在着composer.lock文件。如果原本就存在这composer.lock文件,那么就会直接根据composer.lock中的版本下载对应的包,此时不再理会composer.json中的配置项。如果不存在composer.lock文件,则根据composer.json文件中的配置下载对应的版本,并生成composer.json对应的composer.lock文件。composer.lock又称为锁定文件,生成对应的composer.lock之后,composer.json和composer.lock共同对版本进行控制。有了composer.lock之后,及时有了新的版本也不会触发新版本的更新,除非手动使用composer update命令进行手动的更新。

开发环境下的依赖

  有的时候我们只是在开发的时候才会依赖于某个具体的包,但是在发行的版本中并不需要这样的包,为了达到这种要求可以使用require-dev引入开发环境下的包依赖。如下:

1
2
3
4
5
{
    "require-dev":{
        "xxxx/xxxx": "x.x.* @dev"
    }
}

自动加载类

通过composer.json或者composer.lock,所依赖的第三方库已经被下载下来了,那么在我们的项目中怎么使用这些第三方库呢?最简单的方式就是通过include或者require将所需要的类文件包含进来,但是这种方式需要我们自己去寻找所使用的类对应的类文件,这就存在和PHP语言中直接使用include和require加载所需要的类存在同样的弊端,一种比较简单的方式当然就是使用composer提供的类的自动加载机制了。类似于PHP的自动加载机制,composer提供了autoload实现类的自动加载。

成功运行composer install之后,只要调用生成的vendor目录下的autoload.php文件就可以调用通过composer.json加载的类了。以上面所述的项目中需要monolog包为例,通过可以通过下面的方式使用monolog包中的Logger类。

1
2
include "vendor/autoload.php";
$log = new Monolog\Logger("name");

当然,除了使用第三方库中提供的类之外,还可以使用自己的定义的类。Composer提供了autoload关键字用于加载我们自己提供的类,假如我们定义了一个有关测试的类,如下:

1
2
3
4
5
6
7
class ClassTest{
    public function test()
    {
        echo "hello world!";
    }
}

将该类放在lib目录下的ClassTest.php文件夹下面,那么怎么让composer加载自己定义的类呢?

1. 在composer.json中加入autoload关键字

1
2
3
"autoload":{
    "files":["lib/ClassTest.php"];
}

files键对应的值是一个数组且改值是相对于文件应用根目录的文件的路径。在composer.json中加入上述的关键字之后,在命令行下运行composer dump-autoload就可以让composer重建加载信息,那么就可以在其他的文件中使用这个类了。

上述所述的方法和PHP中直接使用include和require存在一样的弊端,每个类都需要重新书写加载文件,费时费力。

2. composer.json中加入classmap关键字

相比于每个类文件都需要加载一次的做法,使用classmap关键字,能够减少程序员的负担,只需要将文件所在的目录添加在classmap的值中即可,如下:

1
"classmap" : ["lib"]

其实这需要建立一种类名到类所在的文件的映射关系。当需要相应的类的时候,composer通过类名找到对应的类文件名,将相应的类include进来。但是这同样存在一个问题就是,每增加一个类都需要重新运行一次composer dump-autoload重新创建类名到文件之间的映射关系,从而将对应的类加载进来。虽然比files关键字节省了功夫,但是依然不能完全自动加载所需要的类。

3. 基于PHP规范的自动加载方式

  针对PHP这种编程语言,到目前FIG指定了五个规范,分别如下:

  • PSR0:自动加载;
  • PSR1:基本代码规范;
  • PSR2:代码样式规范;
  • PSR3:日志接口规范;
  • PSR4:自动加载规范;

看上去PSR4与PSR0是重复了,但是PSR4规范比较干净,可以看成PSR0规范的升级版。二者最重要区别在于:PSR0规范中,下划线会被转换为目录分隔符,但是PSR4中下划线不具有特殊的含义。二者都是通过特定的目录、文件名以及类名,实现快速查找到类文件,并将相应的类加载进来。

PSR0和PSR4要求有个命名的空间,对上述的ClassTest类做相应的修改如下:

1
2
3
4
5
6
7
8
9
<?php
namespace ClassTestLib;
class ClassTest{
    public function test()
    {
        echo "hello world!";
    }
}

那么对应的文件的路径应该改为\lib\ClassTestLib\ClassTest.php,此时修改composer.json中的autoload如下:

1
2
3
4
5
"autoload":{
    "psr-0":{
        "ClassTestLib":"lib/"
    }  
}

可能你发现psr0的值有一些奇怪,是的。在这里ClassTestLib代表的是命名空间,而”lib”是目录名。加载对应的类文件的时候,搜索的路径是lib/ClassTestLib,而不是ClassTestLib/lib,这是在书写composer.json的时候需要注意的一点。

如果命名空间中存在着“\”,则在书写对应的composer.json的时候需要在相应的“\”再添加一个“\”。例如,如果命名空间改为ClassTest\Lib,相应的对应与应用根目录的路径名称应该变为\lib\ClassTest\Lib\ClassTest.php,对应的composer.json中的autoload应该变为:

1
2
3
4
5
"autoload":{
    "psr-0":{
        "ClassTest\\Lib":"lib/"
    }  
}

 

小结:以上是关于composer的基本使用方法,后续在遇到相关的问题,和大家在一起学习。