竹磬网-邵珠庆の日记 生命只有一次,你可以用它来做些更多伟大的事情–Make the world a little better and easier


282月/181

【第三方工具】Gogs使用详解

发布在 邵珠庆

https://gogs.io

Gogs使用介绍

Gogs是一款类似Github(国内有码市)的开源文件/代码管理系统(基于Git)

目前功能基本介绍
远程代码仓库管理
代码仓库权限分配、管理
团队管理
代码审查

(1)注册

自动草稿


(2)基本功能介绍

主面板说明

自动草稿


图中1表示自己个人账户下的仓库(所有权属于自己)
图中2表示自己参与的仓库(所有权不属于自己)

注意
自己个人账户下的仓库一般为自己创建,或者其他仓库所有者转让仓库。自己对该仓库具有全部权限(写入/删除文件、增加成员、删除成员、合并分之、审核分之)


新建仓库

自动草稿


在主面板中点击我的仓库右侧的” ”按钮后进入新建仓库页面,在此页面中我们需哟啊输入仓库的基本描述,并设置可见属性.
注意
在创建仓库按钮的上方有一个复选框“使用选定文件和模板初始化仓库”。
这里如果不选,则会生成一个空仓库,我们需要在本地生成一个仓库(或者原有仓库),然后将本地仓库的远程仓库地址设置成我们在Gogs中新建的仓库地址。


仓库使用基介绍

自动草稿


图中1仓库中的文件管理页面
图中2仓库的工单管理页面
图中3仓库的合并请求管理(代码审查、合并)
图中4查看代码的分支
图中5在浏览器中上传和下载文件(不依赖Git)
图中6当前仓库的远程地址(将其拷贝下来,将本地的对应仓库的origin地址设置)
图中7当前仓库的文件阅览


基于浏览器进行文件上传下载

自动草稿
可以直接在浏览器中进行文件上传


自动草稿
可以直接在浏览器查看对应文档,或者下载文档


(4)组织管理

Git魅力不仅仅体现在对代码的管理,还有有效的管理团队合作上

组织管理介绍

Gogs也专门提供了组织管理功能(组织可以代表一个公司,可以在组织下建立仓库、添加组织成员,然后通过创建和设置团队,将组织名下的仓库分别授权给不同的成员)


自动草稿
图中点击”我的组织”后面的“+”号可以新建组织


自动草稿


图中1显示当前组织下的仓库,点击创建新仓库可以添加新的组织
图中2显示当前组织中的成员,可以点击邀请其他人,添加新的成员
图中3显示当前组织下设置的团队(每个团对可以分别添加组织下的不同仓库和不同成员,并设置该团队权限(写入、阅读))


自动草稿


图中1显示该团队有4名成员
图中2显示该团队拥有当前组织的2个仓库的权限
图中3显示该团队对yo拥有的2个仓库具有读取和写入的权限

265月/170

Nginx使用的php-fpm的两种进程管理方式及优化

发布在 邵珠庆

背景
最近将Wordpress迁移至阿里云。由于自己的服务器是云服务器,硬盘和内存都比较小,所以内存经常不够使,通过Linux命令查看后,发现启动php-fpm进程数有20多个,占用了将近1G的内存,整个服务器才1.5G的内存,最后通过对php-fpm进程数优化解决了此问题,服务器多节省出600M的内存,将php-fpm的优化方法和大家分享下。
备注:目前根据nginx、fpm-php进行了内存优化,详情见相关资料
php-fpm优化

1、php-fpm优化参数介绍
他们分别是:pm、pm.max_children、pm.start_servers、pm.min_spare_servers、pm.max_spare_servers。

pm:表示使用那种方式,有两个值可以选择,就是static(静态)或者dynamic(动态)。
在更老一些的版本中,dynamic被称作apache-like。这个要注意看配置文件的说明。

下面4个参数的意思分别为:
pm.max_children:静态方式下开启的php-fpm进程数量
pm.start_servers:动态方式下的起始php-fpm进程数量
pm.min_spare_servers:动态方式下的最小php-fpm进程数
pm.max_spare_servers:动态方式下的最大php-fpm进程数量

区别:
如果dm设置为 static,那么其实只有pm.max_children这个参数生效。系统会开启设置数量的php-fpm进程。
如果dm设置为 dynamic,那么pm.max_children参数失效,后面3个参数生效。
系统会在php-fpm运行开始 的时候启动pm.start_servers个php-fpm进程,
然后根据系统的需求动态在pm.min_spare_servers和pm.max_spare_servers之间调整php-fpm进程数

2、服务器具体配置
对于我们的服务器,选择哪种执行方式比较好呢?事实上,跟Apache一样,运行的PHP程序在执行完成后,或多或少会有内存泄露的问题。
这也是为什么开始的时候一个php-fpm进程只占用3M左右内存,运行一段时间后就会上升到20-30M的原因了。
对于内存大的服务器(比如8G以上)来说,指定静态的max_children实际上更为妥当,因为这样不需要进行额外的进程数目控制,会提高效率。
因为频繁开关php-fpm进程也会有时滞,所以内存够大的情况下开静态效果会更好。数量也可以根据 内存/30M 得到,比如8GB内存可以设置为100,
那么php-fpm耗费的内存就能控制在 2G-3G的样子。如果内存稍微小点,比如1G,那么指定静态的进程数量更加有利于服务器的稳定。
这样可以保证php-fpm只获取够用的内存,将不多的内存分配给其他应用去使用,会使系统的运行更加畅通。
对于小内存的服务器来说,比如256M内存的VPS,即使按照一个20M的内存量来算,10个php-cgi进程就将耗掉200M内存,那系统的崩溃就应该很正常了。
因此应该尽量地控制php-fpm进程的数量,大体明确其他应用占用的内存后,给它指定一个静态的小数量,会让系统更加平稳一些。或者使用动态方式,
因为动态方式会结束掉多余的进程,可以回收释放一些内存,所以推荐在内存较少的服务器或VPS上使用。具体最大数量根据 内存/20M 得到。
比如说512M的VPS,建议pm.max_spare_servers设置为20。至于pm.min_spare_servers,则建议根据服务器的负载情况来设置,比如服务器上只是部署php环境的话,比较合适的值在5~10之间。

本服务器配置

1、服务器基本信息:
硬盘:数据盘30G、系统盘20G
内存:1.5G
CPU:双核
系统:CentOS 6.3 64位
带宽:独享2M
2、部署的应用
Git、SVN、Apache、Tomcat、PHP、Nginx、Mysql、JDK
3、优化后的参数
pm = dynamic
pm.start_servers = 5
pm.min_spare_servers = 2
pm.max_spare_servers = 8

 

max_children=40 , 每个children平均占用20M-30M内存,children越多,可以同时接受的并发数量越多,一般children的值是网站最高并发数+浮动值,这值再×内存占用,就是你需要用到的内存。
max_requests = N 是指当每个children接受了N次请求以后,就会把自己杀死,然后重新建立一个children。
PV / max_children = 每一个children接受的request次数
比如上面的值是1000,而你定义的是10240,那么fpm要超过10天才能杀死children并重建,这样如果存在内存泄露的话,就会导致进程占用过多的内存而无法释放,从而使fpm的处理能力降低,还会产生一些莫名其妙的错误。
但是如果你把这个值设置的过小,fpm频繁的杀死children并重建,也会导致额外的开销。
最好的优化当然是根据你网站的运行情况,去不断的调试,找到一个平衡点。

205月/170

百度文字转语音免费接口使用实例

发布在 邵珠庆

1、接口

http://tts.baidu.com/text2audio?lan=zh&ie=UTF-8&spd=2&text=你要转换的文字

上述接口的url,在浏览器上直接打开,即可听到文字转换后的语音。

 

lan=zh:语言是中文,如果改为lan=en,则语言是英文。

ie=UTF-8:文字格式。

spd=2:语速,可以是1-9的数字,数字越大,语速越快。

text=**:这个就是你要转换的文字。

2、js调用

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <title>Document</title>
  6. </head>
  7. <body>
  8.     <form action="" method="post">
  9.         <table align="center">
  10.             <tr>
  11.                 <td><input type="text" id='val' placeholder='你要装换的文字'></td>
  12.                 <td><input type="button" value="提交" onclick="fun()"></td>
  13.             </tr>
  14.         </table>
  15.     </form>
  16. </body>
  17. </html>
  18. <script type="text/javascript">
  19. function fun()
  20. {
  21.     var val=document.getElementById("val").value;
  22.     var zhText = val;
  23.     zhText = encodeURI(zhText);
  24.     document.write("<audio autoplay=\"autoplay\">");
  25.     document.write("<source src=\"http://tts.baidu.com/text2audio?lan=zh&ie=UTF-8&spd=2&text="+ zhText +"\" type=\"audio/mpeg\">");
  26.     document.write("<embed height=\"0\" width=\"0\" src=\"http://tts.baidu.com/text2audio?lan=zh&ie=UTF-8&spd=2&text="+ zhText +"\">");
  27.     document.write("</audio>");
  28. }
  29. </script>

 

185月/170

优雅的使用 phpStorm 开发工具

发布在 邵珠庆

按照惯例依然是从百科上复制一条简介: PhpStorm 是 JetBrains 公司开发的一款商业的 PHP 集成开发工具。PhpStorm可随时帮助用户对其编码进行调整,运行单元测试或者提供可视化debug功能和智能HTML/CSS/JavaScript/PHP编辑、代码质量分析、版本控制集成(SVN、GIT)、调试和测试等功能。另外,它还是跨平台。在Windows和MacOS下都可以使用。PhpStorm-让开发更智能,而不是更困难。

听说phpStorm 10支持php7呃

优点

  1. 跨平台。
  2. 对PHP支持refactor功能。
  3. 自动生成phpdoc的注释,非常方便进行大型编程。
  4. 内置支持Zencode。
  5. 生成类的继承关系图,如果有一个类,多次继承之后,可以通过这个功能查看他所有的父级关系。
  6. 支持代码重构,方便修改代码。
  7. 拥有本地历史记录功能(local history功能)。
  8. 方便的部署,可以直接将代码直接upload到服务器。

总之它很牛逼就是了,什么都能干

快捷键

phpStorm有非常非常多并且好用的的快捷键,我下面就举一些经常用的的快捷键演示,还有一些不常用的就不举例了,绝对能提高你开发的效力率...

(Windows与Mac类似,只要把 command 键换成 ctrl )

查询相关

  • command + f 查找当前文件
  • command + r 查找替换
  • command + e 打开最近的文件
  • command + shift + o 快速查询文件
  • command + shift + f 关键字查找,更强大的查询器(机器不好的,最好还是先确定一下目录)
  • command + shift + r 高级替换
  • command + alt + b 找到当剪类的所有子类
  • alt + shift + c 查找最近修改的文件
  • alt + f7 直接查询选中的字符
  • ctrl + f7 文件中查询选中字符
  • command + 鼠标点击 跳到类或方法或变量等声明处
  • command + shift + tab 切换tab页文件
  • command + shift + +,- 展开或缩起
  • command + . 折叠或展开选中的代码

自动代码

  • alt + 回车 导入包,自动修正
  • command + n 快事为每个成员属性生成 getter 及 setter 方法
  • ctrl + i 快速生成插入魔术方法
  • ctrol + o 复写父类方法
  • command + alt + l 对当前文件进行格式化排版
  • command + d 复制当剪行
  • command + / // 注释
  • command + shift + / / / 注释

command + n 举个例子

我创建了一个 Person 类在 /Entity/ 目录下,然后我设置一些私有的属性如下代码:

namespace Entity;

class Person
{
    private $sign = '';

    private $name = '';

    private $age  = 0;

    private $work = '';

    private $sex  = '女';
}

然后咱们使用 command + n 在弹出来的窗口选择"PHPDoc Blocks..." 如下图:

再再弹出的窗口选择所有属性再点"OK":

namespace Entity;

/**
 * Class Person
 * @package Entity
 */
class Person
{
    /**
     * @var string
     */
    private $sign = '';

    /**
     * @var string
     */
    private $name = '';

    /**
     * @var int
     */
    private $age  = 0;

    /**
     * @var string
     */
    private $work = '';

    /**
     * @var string
     */
    private $sex  = '女';
}

然后它就对刚刚所选择属性加上了注释...... 是不是灰常神奇。

ok,咱们继续,再次使用 command + n 键选择 Contructor... 弹出需要进行传参赋值的属性:

    /**
     * Person constructor.
     * @param string $sign
     */
    public function __construct($sign)
    {
        $this->sign = $sign;
    }

如果不选择的话将不需要对成员属性进行设置。

然后咱们再来看看其他功能,比如"Implement Methods..."这个是快速生成魔术方法。

通常咱们设置、获取一个成员属性时最好不要直接使用 $person->name = $name 这种方式进行设置参数或取得参数值, 建议是对每个属性都开放一个 gettersetter 方法,这样可以很方便得对传进或传出去的值进行处理,这就是上面我为什么要把成员属性设置置为私有的原因之一

同样的 command + n 选择"Getters and Stetters" 然后选择所有属性,它就会把所有的属性设置 gettersetter 方法,这里要注意的是 Personsign 是唯一的,不可进行修改,所以咱们要把设置 sign 的方法去掉。注意: 最好 setter 方法设置完后返回当剪对象,这样的话咱们就可以连写了并且phpStorm的提示还相当友好 下面有例子:

    /**
     * @return string
     */
    public function getSign()
    {
        return $this->sign;
    }

    /**
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @param string $name
     * @return $this
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    /**
     * @return int
     */
    public function getAge()
    {
        return $this->age;
    }

    /**
     * @param int $age
     * @return $this
     */
    public function setAge($age)
    {
        $this->age = $age;

        return $this;
    }

    /**
     * @return string
     */
    public function getWork()
    {
        return $this->work;
    }

    /**
     * @param string $work
     * @return $this
     */
    public function setWork($work)
    {
        $this->work = $work;

        return $this;
    }

    /**
     * @var string
     */
    private $sex  = '女';

    /**
     * @return string
     */
    public function getSex()
    {
        return $this->sex;
    }

    /**
     * @param string $sex
     * @return $this
     */
    public function setSex($sex)
    {
        $this->sex = $sex;

        return $this;
    }

连写的例子:

use Entity\Person;
$person = new Person();
$person->setName("蛋蛋")
    ->setAge(17)
    ->setWork('student');

最后再演示一个快速复写被继承类的功能。咱们新建一个 Man 类,然后继承 Person 类,上面的Person类缺省是女性别,所以我们需要重写它并且加上"中国男人"。同样的使用 command + n 打开快捷窗口选择 "Override Methods..." 弹出来可被复写的方法:

然后咱们选择 getSexsetSex 方法,然后确定,在 Man 方法下生成以下方法。

namespace Entity;

/**
 * Class Man
 * @package Entity
 */
class Man extends Person
{
    /**
     * @return string
     */
    public function getSex()
    {
        return parent::getSex(); // TODO: Change the autogenerated stub
    }

    /**
     * @param int $sex
     * @return $this
     */
    public function setSex($sex)
    {
        return parent::setSex($sex); // TODO: Change the autogenerated stub
    }
}

咱们把 return parent::getSex()return parent::setSex( $age ) 删除掉,不需要这样,然后改成如下模式。

    /**
     * @return string
     */
    public function getSex()
    {
        if ( ! mb_strpos(parent::getSex(), "中国") )
            return "中国".parent::getSex();
        return parent::getSex();
    }

    /**
     * @param int $sex
     * @return $this
     */
    public function setSex($sex)
    {
        if( ! mb_strpos($sex, "中国") )
            $sex = "中国".$sex;
        return parent::setSex($sex);
    }

碉堡了有木有。

工具类等

看起来好多的样纸,我懒,不想讲可不可以?我就挑几个好不好?

  • 连拉ssh 照着配就行了,很简单

  • composer 这个也很明了吧,不多说了,平时咱们都是通过命令行来实现的
  • vagrant 这个phpstorm 10集成了vagrant,介于咱们自己已经搭建好了自己的vagrant环境,就不使用phpstorm所集成的啦

参考: 《使用Virtual Box和Vagrant搭建开发环境》

Database 工具

phpStorm所集成的database工具十分强大,当然它还有单独的database工具叫做: DataGrip,当然需要独立购买,咱们phpStorm有集成,就使用它好啦哈哈....(咱们的PhpStorm可是花钱买的,请支持正版)

Database工具一般在右侧栏,如果没有的话搜一下就好了,多简单的事儿呀...

开始创建一个数据库连接吧...

选择如上图的那个"+"号,然后选择 Data Source 数据来源,再选择数据库类型,一般咱们都是使用mysql吧,这次咱们试试新的,比如 SQLite

选择 sqlite 数据文件的地址,然后选择驱动,如果没有的话得先下载安装sqlite的驱动插件,这个很简单,在Driver下有提示,照做就是了...

咱们先看一下mysql的配制吧...

mysql的也非常简单,如果需要ssh/ssl连接的话,需要在SSH/SSL选项卡上配配地址入连接密码或sshkey...

配制好了,打开选择的数据库:

上图是连接的数据库的表及表字段信息... 来演示一下查询... 点击那"QL"样的dos窗口图标会弹出一个tab页,咱们可以在这里写sql语句。

咱们查询 User 表下的所有数据,可以看到会有相当提示,这是相当的好使啊...查询完成后在下面的 Database Console 上会有显示表数据,可对它进行修改,等等操作增加数据也可以。

快捷键 command + alt + l 不但对代码进行格式化,也sql语句也是非常有效的,如上图。

在"Database Console"栏上点"Output"选项卡可以查看sql语句执行的情况、记录及所消耗的时间等等信息...

  • command + 回车 执行sql语句或执行选中的sql语句

关于database工具的用法还有很多很多,我就不一一讲解了,大家可以自己慢慢去研究,真的非常好用

CVS 和 Git

  • command + k
  • command + shift + k

关于FTP的配制,由于我不推荐使用,所以这里就不多说啦!

都到这了,那咱们就说说在phpStorm上如何使用git工具吧

算了,还是举一个例子吧,配辣么多太累了,一会我看下有没有已经配好的,如果有的话一会拉出来截个图看看就行吧,反正现在svn用得也比较少了,还是git用得爽,分布式嘛,离线嘛,多好...关于 svn -> git 可以参考我之前写的一篇文章

《将代码库从Svn迁移Git》

从git服务器上把代码抓到本地

选择 CVS -> Checkout from Version Control -> Git

在弹出的窗口输入自己的git仓库信息:

注意 conle 的时间如果没有设置你的github账号的话可能会提示你输入账号信息,咱们输入就行了。如果需要修改的话则在设置里面进行修改,咱们可以使用 command + , 打开"Preferences" 然后找到"Version Control"选项目的"GitHub"进行设置,还有"Git"路径。

从mster创建分支

创建分支以通过命令行进行创建,咱们可以通过phpstrom的窗口进行创建,如下:

这个东西在右下角,"Git:master" 然后弹出上面窗口选择"New Branch" 然后输入新分支的名称就好了,它会自动切换到新分支下。

是不是超级简单呀...

提交代码至远程分支

当咱们修改完代码后,咱们需要把代码提交到远程分支上,使用快捷键 command + k 提交相当修改后的代码,双击文件可以进行对比。在"Commit Message"写上修改的东西然后点提交,这时就把代码提交到本地分支上了。

不使用快捷键的话,可以使用"CVS -> Commit Changes"提交,也会弹出下面窗口...

提交到本地分支后,咱们需要把代码推到远程分支上,所以需要使用快捷键: command + shif + k 提交远程分支...

也可以使用"CVS -> Git -> Push"进行提交...效果是一样的

注意svn木有 command + shift + k 这一步

合并分支

分并非常简单,只要选择需要合并的分支,然后merge就行了,如下图:

这样就合并完成,当然,如果有冲突的话会提交有冲突,并让你解决,如果没有的话就直接合并成功了...然后就可以push了......

Compare 是对合并的分支进行对比...

使用svn...

灰常抱歉,我电脑上木有找到相关Svn项目的代码,就不多说了...

安装插件

这里讲一个javascript 的安装,使用快捷键 cmd + , 打开 Preferances

安装 JavaScript 插件

Languages & Frameworks -> Javascript -> Libraries

选择add需要的框架

安装symfony2插件,搜索插件,然后点install

然后重启phpStorm 就完事了....

注意

  • 灰色+波浪线: 变量未使用
  • 黄色波浪线: 变量未名单词拼写问题
  • 红色波浪线: 变量未定义
  • 还有好多我就不一一举例了,可能是因为我代码写得太好,出错的东西比较少吧...

右边栏出现红色,这点是必须要杜绝的,好的代码不应该出现红色的任何提示...一旦出现一定要马上解决,好的代码不应该出现一个黄、红色的提示。

TODO 表示待办事件,当提交到vcs、svn或git的时候,会提示是还有未处理的事件,需要确认提交。

93月/170

Linux技巧:Vimdiff 使用

发布在 邵珠庆

在 IBM Bluemix 云平台上开发并部署您的下一个应用。

开始您的试用

源程序文件(通常是纯文本文件)比较和合并工具一直是软件开发过程中比较重要的组成部分。现在市场上很多功能很强大的专用比较和合并工具,比如 BeyondCompare;很多IDE 或者软件配置管理系统,比如Eclipse, Rational ClearCase都提供了内建的功能来支持文件的比较和合并。

当远程工作在Unix/Linux平台上的时候,恐怕最简单而且到处存在的就是命令行工具,比如diff。可惜diff的功能有限,使用起来也不是很方便。作为命令行的比较工具,我们仍然希望能拥有简单明了的界面,可以使我们能够对比较结果一目了然;我们还希望能够在比较出来的多处差异之间快速定位,希望能够很容易的进行文件合并……。而Vim提供的diff模式,通常称作vimdiff,就是这样一个能满足所有这些需求,甚至能够提供更多的强力工具。在最近的工作中,因为需要做很多的文件比较和合并的工作,因此对Vimdiff的使用做了一个简单的总结。我们先来看看vimdiff的基本使用。

启动方法

首先保证系统中的diff命令是可用的。Vim的diff模式是依赖于diff命令的。Vimdiff的基本用法就是:

# vimdiff  FILE_LEFT  FILE_RIGHT

或者

# vim -d  FILE_LEFT  FILE_RIGHT

图一就是vimdiff命令的执行结果的画面。

图1

从上图我们可以看到一个清晰的比较结果。屏幕被垂直分割,左右两侧分别显示被比较的两个文件。两个文件中连续的相同的行被折叠了起来,以便使用者能把注意力集中在两个文件的差异上。只在某一文件中存在的行的背景色被设置为蓝色,而在另一文件中的对应位置被显示为绿色。两个文件中都存在,但是包含差异的行显示为粉色背景,引起差异的文字用红色背景加以突出。

除了用这种方法启动vim的diff模式之外,我们还可以用分割窗口命令来启动diff模式:

# vim FILE_LEFT

然后在vim的ex模式(也就是"冒号"模式)下输入:

:vertical diffsplit FILE_RIGHT

也可以达到同样的效果。如果希望交换两个窗口的位置,或者希望改变窗口的分割方式,可以使用下列命令:

1. Ctrl-w K(把当前窗口移到最上边)
2. Ctrl-w H(把当前窗口移到最左边)
3. Ctrl-w J(把当前窗口移到最下边)
4. Ctrl-w L(把当前窗口移到最右边)

其中1和3两个操作会把窗口改成水平分割方式。

 

回页首

光标移动

接下来试试在行间移动光标,可以看到左右两侧的屏幕滚动是同步的。这是因为"scrollbind"选项被设置了的结果,vim会尽力保证两侧文件的对齐。如果不想要这个特性,可以设置:

:set noscrollbind

可以使用快捷键在各个差异点之间快速移动。跳转到下一个差异点:

]c

反向跳转是:

[c 1="</div>" 2="如果在命令前加上数字的话,可以跳过一个或数个差异点,从而实现跳的更远。比如如果在位于第一个差异点的行输入"2" language="</pre>"][/c]c",将越过下一个差异点,跳转到第三个差异点。

 

回页首

文件合并

文件比较的最终目的之一就是合并,以消除差异。如果希望把一个差异点中当前文件的内容复制到另一个文件里,可以使用命令

dp (diff "put")

如果希望把另一个文件的内容复制到当前行中,可以使用命令

do (diff "get",之所以不用dg,是因为dg已经被另一个命令占用了)

如果希望手工修改某一行,可以使用通常的vim操作。如果希望在两个文件之间来回跳转,可以用下列命令序列:

Ctrl-w, w

在修改一个或两个文件之后,vimdiff会试图自动来重新比较文件,来实时反映比较结果。但是也会有处理失败的情况,这个时候需要手工来刷新比较结果:

:diffupdate

如果希望撤销修改,可以和平常用vim编辑一样,直接

<ESC>, u

但是要注意一定要将光标移动到需要撤销修改的文件窗口中。

 

回页首

同时操作两个文件

在比较和合并告一段落之后,可以用下列命令对两个文件同时进行操作。比如同时退出:

:qa (quit all)

如果希望保存全部文件:

:wa (write all)

或者是两者的合并命令,保存全部文件,然后退出:

:wqa (write, then quit all)

如果在退出的时候不希望保存任何操作的结果:

:qa! (force to quit all)
 

回页首

上下文的展开和查看

比较和合并文件的时候经常需要结合上下文来确定最终要采取的操作。Vimdiff 缺省是会把不同之处上下各 6 行的文本都显示出来以供参考。其他的相同的文本行被自动折叠。如果希望修改缺省的上下文行数,可以这样设置:

:set diffopt=context:3

可以用简单的折叠命令来临时展开被折叠的相同的文本行:

zo (folding open,之所以用z这个字母,是因为它看上去比较像折叠着的纸)

然后可以用下列命令来重新折叠:

zc (folding close)

下图是设置上下文为3行,并展开了部分相同文本的vimdiff屏幕:

 

回页首

结论

在无法使用图形化的比较工具的时候,或者在需要快速比较和合并少量文件的时候,Vimdiff是最好的选择。

 

211月/160

Linux下如何使用命令同步时钟

发布在 邵珠庆

linux的系统时钟在很多地方都要用到,要是不准,就会出现一些奇怪的问题;

在Linux中,用于时钟查看和设置的命令主要有date、hwclock和clock。Linux时钟分为系统时钟(System Clock)和硬件(Real Time Clock,简称RTC)时钟。系统时钟: 是指当前Linux Kernel中的时钟,硬件时钟: 是主板上由电池供电的时钟,这个硬件时钟可以在BIOS中进行设置。

当Linux启动时,硬件时钟会去读取系统时钟的设置,然后系统时钟就会独立于硬件运作。

Linux 中的所有命令(包括函数)都是采用的系统时钟设置。在Linux中,用于时钟查看和设置的命令主要有date、hwclock和clock。其中,clock和hwclock用法相近,只用一个就行,只不过clock命令除了支持x86硬件体系外,还支持Alpha硬件体系。

  1、 date

查看系统时间

# date

设置系统时间

# date –set “07/07/06 10:19″ //(月/日/年时:分:秒)

  2、hwclock/clock

查看硬件时间

# hwclock –show //或者

# clock –show

设置硬件时间

# hwclock –set –date=”07/07/06 10:19″ (月/日/年 时:分:秒) 或者

# clock –set –date=”07/07/06 10:19″ (月/日/年 时:分:秒)

  3、硬件时间和系统时间的同步

按照前面的说法,重新启动系统,硬件时间会读取系统时间,实现同步,

但是在不重新启动的时候,需要用hwclock或clock命令实现同步。

硬件时钟与系统时钟同步:

# hwclock –hctosys // (hc代表硬件时间,sys代表系统时间)或者

# clock –hctosys

系统时钟和硬件时钟同步:

# hwclock –systohc // 或者

# clock –systohc

  4. 和外部的NTP时间服务器同步

$ service ntpd stop

这一步是必须的,否则出出现:

25 Nov 18:10:34 ntpdate[2106]: the NTP socket is in use, exiting

的失败提示;

$ ntpdate ntp.sjtu.edu.cn

正常返回如下:

25 Nov 18:14:34 ntpdate[2164]: adjust time server 202.120.2.101 offset -0.006107 sec

错误返回如:

25 Nov 18:13:44 ntpdate[2158]: no server suitable for synchronization found

$ service ntpd start

$ chkconfig ntpd on

$ clock -w

还可以写进定时任务中,以做定时的时钟同步:

$ crontab -e

05 * * * * /usr/sbin/ntpdate ntp.sjtu.edu.cn 》 /dev/null 2》&1

05 17 * * * /sbin/clock -w

附上中国大概能用的NTP时间服务器地址

server 133.100.11.8 prefer

server 210.72.145.44

server 203.117.180.36

server 131.107.1.10

server time.asia.apple.com

server 64.236.96.53

server 130.149.17.21

server 66.92.68.246

server www.freebsd.org

server 18.145.0.30

server clock.via.net

server 137.92.140.80

server 133.100.9.2

server 128.118.46.3

server ntp.nasa.gov

server 129.7.1.66

server ntp-sop.inria.frserver 210.72.145.44(中国国家授时中心服务器IP地址)

server ntp.sjtu.edu.cn(上海交通大学网络中心NTP服务器地址)

上面就是使用命令同步Linux时钟的方法介绍了,一般使用data、hwclock和clock命令,而data命令是比较常用的命令,如果你的系统时钟不同步,那就赶紧改过来吧。

1710月/160

MySQL中的mysqldump命令使用详解

发布在 邵珠庆

就用 --ignore-table=dbname.tablename参数就行了。

mysqldump -uusername -ppassword -h192.168.0.1 -P3306 dbname --ignore-table=dbname.dbtanles > dump.sql

导出要用到MySQL的mysqldump工具基本用法是:
shell> mysqldump [OPTIONS] database [tables]
如果你不给定任何表,整个数据库将被导出。
通过执行mysqldump --help,你能得到你mysqldump的版本支持的选项表。
注意,如果你运行mysqldump没有--quick或--opt选项,mysqldump将在导出结果前装载整个结果集到内存中,如果你正在导出一个大的数据库,这将可能是一个问题。
mysqldump支持下列选项:

--add-locks 在每个表导出之前增加LOCK TABLES并且之后UNLOCK
TABLE。(为了使得更快地插入到MySQL)。
--add-drop-table 在每个create语句之前增加一个drop table。
--allow-keywords 允许创建是关键词的列名字。这由表名前缀于每个列名做到。
-c, --complete-insert 使用完整的insert语句(用列名字)。
-C, --compress 如果客户和服务器均支持压缩,压缩两者间所有的信息。
--delayed 用INSERT DELAYED命令插入行。
-e, --extended-insert 使用全新多行INSERT语法。(给出更紧缩并且更快的插入语句)
-#, --debug[=option_string] 跟踪程序的使用(为了调试)。
--help 显示一条帮助消息并且退出。
--fields-terminated-by=...
--fields-enclosed-by=...
--fields-optionally-enclosed-by=...
--fields-escaped-by=...
--fields-terminated-by=... 这些选择与-T选择一起使用,并且有相应的LOAD DATA
INFILE子句相同的含义。 LOAD DATA INFILE语法。
-F, --flush-logs 在开始导出前,洗掉在MySQL服务器中的日志文件。
-f, --force, 即使我们在一个表导出期间得到一个SQL错误,继续。
-h, --host=.. 从命名的主机上的MySQL服务器导出数据。缺省主机是localhost。
-l, --lock-tables. 为开始导出锁定所有表。
-t, --no-create-info 不写入表创建信息(CREATE TABLE语句)
-d, --no-data 不写入表的任何行信息。如果你只想得到一个表的结构的导出,这是很有用的!
--opt 同--quick --add-drop-table --add-locks --extended-insert --lock-tables。 应该给你为读入一个MySQL服务器的尽可能最快的导出。
-pyour_pass, --password[=your_pass] 与服务器连接时使用的口令。如果你不指定“=your_pass”部分,mysqldump需要来自终端的口令。
-P port_num, --port=port_num 与一台主机连接时使用的TCP/IP端口号。(这用于连接到localhost以外的主机,因为它使用
Unix套接字。)
-q, --quick 不缓冲查询,直接导出至stdout;使用mysql_use_result()做它。
-S /path/to/socket, --socket=/path/to/socket 与localhost连接时(它是缺省主机)使用的套接字文件。
-T, --tab=path-to-some-directory 对于每个给定的表,创建一个table_name.sql文件,它包含SQL
CREATE 命令,和一个table_name.txt文件,它包含数据。
注意:这只有在mysqldump运行在mysqld守护进程运行的同一台机器上的时候才工作。.txt文件的格式根据--fields-xxx和--lines--xxx选项来定。
-u user_name, --user=user_name 与服务器连接时,MySQL使用的用户名。缺省值是你的Unix登录名。
-O var=option, --set-variable var=option设置一个变量的值。可能的变量被列在下面。
-v, --verbose 冗长模式。打印出程序所做的更多的信息。
-V, --version 打印版本信息并且退出。
-w, --where='where-condition' 只导出被选择了的记录;注意引号是强制的!
"--where=user='jimf'" "-wuserid>1"
"-wuserid<1" 最常见的mysqldump使用可能制作整个数据库的一个备份: mysqldump --opt database >
backup-file.sql
但是它对用来自于一个数据库的信息充实另外一个MySQL数据库也是有用的:
mysqldump --opt database | mysql
--host=remote-host -C database 由于mysqldump导出的是完整的SQL语句,所以用mysql客户程序很容易就能把数据导入了:
shell> mysqladmin create
target_db_name shell> mysql
target_db_name < backup-file.sql 就是  shell> mysql 库名 < 文件名

几个常用用例:
1.导出整个数据库
mysqldump -u 用户名 -p 数据库名 > 导出的文件名
mysqldump -u wcnc -p smgp_apps_wcnc > wcnc.sql
2.导出一个表
mysqldump -u 用户名 -p 数据库名 表名> 导出的文件名
mysqldump -u wcnc -p smgp_apps_wcnc users> wcnc_users.sql
3.导出一个数据库结构
mysqldump -u wcnc -p -d --add-drop-table smgp_apps_wcnc >d:\wcnc_db.sql
-d 没有数据 --add-drop-table 在每个create语句之前增加一个drop table
4.导入数据库
常用source 命令
进入mysql数据库控制台,
如mysql -u root -p

mysql>use 数据库
然后使用source命令,后面参数为脚本文件(如这里用到的.sql)
mysql>source d:\wcnc_db.sql

257月/160

Bootstrap表单验证插件bootstrapValidator使用方法整理

发布在 邵珠庆

文档首页 :
http://bv.doc.javake.cn/api/





 
 
$(document).ready(function() {
   
// 原价、现价同时双验证
$("#original_price").blur(function () {
    $("#form_yanzheng").data('bootstrapValidator').resetForm().validateField('price');
});
$("#price").blur(function () {
    $("#form_yanzheng").data('bootstrapValidator').resetForm().validateField('original_price');
});
 
//表单验证
$('#form_yanzheng').bootstrapValidator({
    message: '值没有被验证',
    feedbackIcons: {
        valid: 'glyphicon glyphicon-ok',
        invalid: 'glyphicon glyphicon-remove',
        validating: 'glyphicon glyphicon-refresh'
    },
    fields: {
        subject: {
            message: 'The username is not valid',
            trigger: 'blur', //失去焦点就会触发
            validators: {
                notEmpty: {
                    message: '商品名称不能为空'
                },
                stringLength: {
                    min: 2,
                    max: 15,
                    message: '输入字符数量错误'
                },
                callback: {
                    message: '商品名称有非法内容',
                    callback: function () {
                        var filter = true;
                        var subject = $("#subject").val();
 
                        if (subject.indexOf("储值卡") >= 0) {
                            filter = false;
                        }
                        if (subject.indexOf("充值卡") >= 0) {
                            filter = false;
                        }
                        if (subject.indexOf("会员卡") >= 0) {
                            filter = false;
                        }
                        if (subject.indexOf("vip卡") >= 0) {
                            filter = false;
                        }
                        if (subject.indexOf("打折卡") >= 0) {
                            filter = false;
                        }
                        if (subject.indexOf("年卡") >= 0) {
                            filter = false;
                        }
                        if (subject.indexOf("美容卡") >= 0) {
                            filter = false;
                        }
                        if (subject.indexOf("健身卡") >= 0) {
                            filter = false;
                        }
 
                        return filter;
                    }
                }
            }
        },
        original_price: {
            trigger: 'blur', //失去焦点就会触发
            message: 'The username is not valid',
            validators: {
                notEmpty: {
                    message: '输入整数或者2位小数'
                },
                regexp: {
                    regexp: /^(\d+\.\d{1,2}|\d+)$/,
                    message: '输入整数或者2位小数'
                },
                callback: {
                    message: '原价要大于等于现价',
                    callback: function () {
                        var op = $('#original_price').val();
                        var pp = $('#price').val();
                        return parseFloat(op) >= parseFloat(pp);
                    }
                }
            }
        },
        price: {
            trigger: 'blur', //失去焦点就会触发
            message: 'The username is not valid',
            validators: {
                notEmpty: {
                    message: '输入整数或者2位小数'
                },
                regexp: {
                    regexp: /^(\d+\.\d{1,2}|\d+)$/,
                    message: '输入整数或者2位小数'
                },
                callback: {
                    message: '原价要大于等于现价',
                    callback: function () {
                        var op = $('#original_price').val();
                        var pp = $('#price').val();
                        return parseFloat(op) >= parseFloat(pp);
                    }
                }
            }
        },
        inventory: {
            trigger: 'blur', //失去焦点就会触发
            message: 'The username is not valid',
            validators: {
                notEmpty: {
                    message: '输入整数或者2位小数'
                },
                between: {
                    min: 0,
                    max: 999999,
                    message: '输入有效库存数量'
                }
            }
        },
        validity_period: {
            trigger: 'blur', //失去焦点就会触发
            message: 'The username is not valid',
            validators: {
                notEmpty: {
                    message: '请正确填写有效天数7-360天'
                },
                between: {
                    min: 7,
                    max: 360,
                    message: '请合理输入使用有效期'
                }
            }
        }
    }
}).on('success.form.bv', function (e) {
 
    var refertype = $('#refertype').val();
    var urlpath = "{:U('Index/" + refertype + "')}";
 
    $.ajax({
        type: "POST",
        url: urlpath,
        data: $('#form_yanzheng').serialize(),
        dataType: 'json',
        success: function (data, statusText, xhr, $form) {
            if (data.type == 'true') {
                swal({
                    title: data.info,
                    text: "",
                    type: "success",
                }, function () {
                    self.location = "{:U('Index/index')}";
                });
 
            } else {
                swal(data.info, "", "error");
                return false;
            }
        }
    });
});
});

264月/160

file_get_contents(“php://input”)的使用方法

发布在 邵珠庆

$data = file_get_contents("php://input");

    php://input 是个可以访问请求的原始数据的只读流。 POST 请求的情况下,最好使用 php://input 来代替 $HTTP_RAW_POST_DATA,因为它不依赖于特定的 php.ini 指令。 而且,这样的情况下 $HTTP_RAW_POST_DATA 默认没有填充, 比激活 always_populate_raw_post_data 潜在需要更少的内存。 enctype="multipart/form-data" 的时候 php://input 是无效的。 

    

 

1, php://input 可以读取http entity body中指定长度的值,由Content-Length指定长度,不管是POST方式或者GET方法提交过来的数据。但是,一般GET方法提交数据 时,http request entity body部分都为空。 

2,php://input 与$HTTP_RAW_POST_DATA读取的数据是一样的,都只读取Content-Type不为multipart/form-data的数据。

学习笔记

 1,Coentent-Type仅在取值为application/x-www-data-urlencoded和multipart/form-data两种情况下,PHP才会将http请求数据包中相应的数据填入全局变量$_POST 

 2,PHP不能识别的Content-Type类型的时候,会将http请求包中相应的数据填入变量$HTTP_RAW_POST_DATA 

 3, 只有Coentent-Type为multipart/form-data的时候,PHP不会将http请求数据包中的相应数据填入php://input,否则其它情况都会。填入的长度,由Coentent-Length指定。 

 4,只有Content-Type为application/x-www-data-urlencoded时,php://input数据才跟$_POST数据相一致。 

 5,php://input数据总是跟$HTTP_RAW_POST_DATA相同,但是php://input比$HTTP_RAW_POST_DATA更凑效,且不需要特殊设置php.ini 

 6,PHP会将PATH字段的query_path部分,填入全局变量$_GET。通常情况下,GET方法提交的http请求,body为空。

 

例子

 1.php用file_get_contents("php://input")或者$HTTP_RAW_POST_DATA可以接收xml数据

 比如:

  getXML.php;//接收XML地址

  

<?php 

     $xmldata = file_get_contents("php://input"); 

     $data = (array)simplexml_load_string($xmldata); 

?> 

 

  这里的$data就是包含xml数据的数组,具体php解析xml数据更新详细的方法

  sendXML.php

 

<?php 

     $xml = '<xml>xmldata</xml>';//要发送的xml 

     $url = 'http://localhost/test/getXML.php';//接收XML地址 

 

     $header = 'Content-type: text/xml';//定义content-type为xml 

     $ch = curl_init(); //初始化curl 

     curl_setopt($ch, CURLOPT_URL, $url);//设置链接 

     curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);//设置是否返回信息 

     curl_setopt($ch, CURLOPT_HTTPHEADER, $header);//设置HTTP头 

     curl_setopt($ch, CURLOPT_POST, 1);//设置为POST方式 

     curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);//POST数据 

     $response = curl_exec($ch);//接收返回信息 

     if(curl_errno($ch)){//出错则显示错误信息 

     print curl_error($ch); 

     } 

     curl_close($ch); //关闭curl链接 

     echo $response;//显示返回信息 

?> 

 

 2.一个手机上传图片到服务器的小程序

  上传文件

   

<?php 

     //@file phpinput_post.php 

     $data=file_get_contents('btn.png'); 

     $http_entity_body = $data; 

     $http_entity_type = 'application/x-www-form-urlencoded'; 

     $http_entity_length = strlen($http_entity_body); 

     $host = '127.0.0.1'; 

     $port = 80; 

     $path = '/image.php'; 

     $fp = fsockopen($host, $port, $error_no, $error_desc, 30); 

     if ($fp){ 

        fputs($fp, "POST {$path} HTTP/1.1\r\n"); 

        fputs($fp, "Host: {$host}\r\n"); 

        fputs($fp, "Content-Type: {$http_entity_type}\r\n"); 

        fputs($fp, "Content-Length: {$http_entity_length}\r\n"); 

        fputs($fp, "Connection: close\r\n\r\n"); 

        fputs($fp, $http_entity_body . "\r\n\r\n"); 

 

        while (!feof($fp)) { 

         $d .= fgets($fp, 4096); 

        } 

        fclose($fp); 

        echo $d; 

     } 

?> 

 

  接收文件

  

<?php 

        /** 

         *Recieve image data 

        **/    

        error_reporting(E_ALL); 

 

     function get_contents() {    

        $xmlstr= file_get_contents("php://input"); 

        $filename=time().'.png'; 

        if(file_put_contents($filename,$xmlstr)){ 

         echo 'success'; 

        }else

         echo 'failed'; 

        } 

        } 

        get_contents(); 

?>

 3.获取HTTP请求原文

  

/** 

     * 获取HTTP请求原文 

     * @return string 

     */ 

    function get_http_raw() { 

     $raw = ''; 

 

     // (1) 请求行 

     $raw .= $_SERVER['REQUEST_METHOD'].' '.$_SERVER['REQUEST_URI'].' '.$_SERVER['SERVER_PROTOCOL']."\r\n"; 

 

     // (2) 请求Headers 

     foreach($_SERVER as $key => $value) { 

        if(substr($key, 0, 5) === 'HTTP_') { 

         $key = substr($key, 5); 

         $key = str_replace('_', '-', $key); 

 

         $raw .= $key.': '.$value."\r\n"; 

        } 

     } 

 

     // (3) 空行 

     $raw .= "\r\n"; 

 

     // (4) 请求Body 

     $raw .= file_get_contents('php://input'); 

 

     return $raw; 

}

111月/150

PHP魔术方法和魔术常量介绍及使用

发布在 邵珠庆

PHP中把以两个下划线__开头的方法称为魔术方法,这些方法在PHP中充当了举足轻重的作用。 魔术方法包括:

  • __construct(),类的构造函数
  • __destruct(),类的析构函数
  • __call(),在对象中调用一个不可访问方法时调用
  • __callStatic(),用静态方式中调用一个不可访问方法时调用
  • __get(),获得一个类的成员变量时调用
  • __set(),设置一个类的成员变量时调用
  • __isset(),当对不可访问属性调用isset()empty()时调用
  • __unset(),当对不可访问属性调用unset()时被调用。
  • __sleep(),执行serialize()时,先会调用这个函数
  • __wakeup(),执行unserialize()时,先会调用这个函数
  • __toString(),类被当成字符串时的回应方法
  • __invoke(),调用函数的方式调用一个对象时的回应方法
  • __set_state(),调用var_export()导出类时,此静态方法会被调用。
  • __clone(),当对象复制完成时调用

__construct()__destruct()

构造函数和析构函数应该不陌生,他们在对象创建和消亡时被调用。例如我们需要打开一个文件,在对象创建时打开,对象消亡时关闭

<?php 
class FileRead
{
    protected $handle = NULL;

    function __construct(){
        $this->handle = fopen(...);
    }

    function __destruct(){
        fclose($this->handle);
    }
}
?>

这两个方法在继承时可以扩展,例如:

<?php 
class TmpFileRead extends FileRead
{
    function __construct(){
        parent::__construct();
    }

    function __destruct(){
        parent::__destruct();
    }
}
?>

__call()__callStatic()

在对象中调用一个不可访问方法时会调用这两个方法,后者为静态方法。这两个方法我们在可变方法(Variable functions)调用中可能会用到。

<?php
class MethodTest 
{
    public function __call ($name, $arguments) {
        echo "Calling object method '$name' ". implode(', ', $arguments). "\n";
    }

    public static function __callStatic ($name, $arguments) {
        echo "Calling static method '$name' ". implode(', ', $arguments). "\n";
    }
}

$obj = new MethodTest;
$obj->runTest('in object context');
MethodTest::runTest('in static context');
?>

__get()__set()__isset()__unset()

当get/set一个类的成员变量时调用这两个函数。例如我们将对象变量保存在另外一个数组中,而不是对象本身的成员变量

<?php 
class MethodTest
{
    private $data = array();

    public function __set($name, $value){
        $this->data[$name] = $value;
    }

    public function __get($name){
        if(array_key_exists($name, $this->data))
            return $this->data[$name];
        return NULL;
    }

    public function __isset($name){
        return isset($this->data[$name])
    }

    public function unset($name){
        unset($this->data[$name]);
    }
}
?>

__sleep()__wakeup()

当我们在执行serialize()unserialize()时,会先调用这两个函数。例如我们在序列化一个对象时,这个对象有一个数据库链接,想要在反序列化中恢复链接状态,则可以通过重构这两个函数来实现链接的恢复。例子如下:

<?php
class Connection 
{
    protected $link;
    private $server, $username, $password, $db;

    public function __construct($server, $username, $password, $db)
    {
        $this->server = $server;
        $this->username = $username;
        $this->password = $password;
        $this->db = $db;
        $this->connect();
    }

    private function connect()
    {
        $this->link = mysql_connect($this->server, $this->username, $this->password);
        mysql_select_db($this->db, $this->link);
    }

    public function __sleep()
    {
        return array('server', 'username', 'password', 'db');
    }

    public function __wakeup()
    {
        $this->connect();
    }
}
?>

__toString()

对象当成字符串时的回应方法。例如使用echo $obj;来输出一个对象

<?php
// Declare a simple class
class TestClass
{
    public function __toString() {
        return 'this is a object';
    }
}

$class = new TestClass();
echo $class;
?>

这个方法只能返回字符串,而且不可以在这个方法中抛出异常,否则会出现致命错误。

__invoke()

调用函数的方式调用一个对象时的回应方法。如下

<?php
class CallableClass 
{
    function __invoke() {
        echo 'this is a object';
    }
}
$obj = new CallableClass;
var_dump(is_callable($obj));
?>

__set_state()

调用var_export()导出类时,此静态方法会被调用。

<?php
class A
{
    public $var1;
    public $var2;

    public static function __set_state ($an_array) {
        $obj = new A;
        $obj->var1 = $an_array['var1'];
        $obj->var2 = $an_array['var2'];
        return $obj;
    }
}

$a = new A;
$a->var1 = 5;
$a->var2 = 'foo';
var_dump(var_export($a));
?>

__clone()

当对象复制完成时调用。例如在设计模式详解及PHP实现:单例模式一文中提到的单例模式实现方式,利用这个函数来防止对象被克隆。

<?php 
public class Singleton {
    private static $_instance = NULL;

    // 私有构造方法 
    private function __construct() {}

    public static function getInstance() {
        if (is_null(self::$_instance)) {
            self::$_instance = new Singleton();
        }
        return self::$_instance;
    }

    // 防止克隆实例
    public function __clone(){
        die('Clone is not allowed.' . E_USER_ERROR);
    }
}
?>

魔术常量(Magic constants)

PHP中的常量大部分都是不变的,但是有8个常量会随着他们所在代码位置的变化而变化,这8个常量被称为魔术常量。

  • __LINE__,文件中的当前行号
  • __FILE__,文件的完整路径和文件名
  • __DIR__,文件所在的目录
  • __FUNCTION__,函数名称
  • __CLASS__,类的名称
  • __TRAIT__,Trait的名字
  • __METHOD__,类的方法名
  • __NAMESPACE__,当前命名空间的名称

这些魔术常量常常被用于获得当前环境信息或者记录日志。

   下一页