用 PHPUnit 写单元测试的时候如果遇到这个问题

基本上是因为你的全局变量中, 包含了闭包. PHPUnit 在执行过程中会对全局变量进行序列化备份, 而PHP 自身的机制限制了序列化对闭包(Closure)的操作. 因此只要禁用序列化全局变量好了.

执行的时候加上 –no-globals-backup 参数即可:

 

phpunit --no-globals-backup xxx

 Mac 命令行下切换 Pac
sudo networksetup -setautoproxyurl 设备 pac 地址
示例
sudo networksetup -setautoproxyurl Wi-Fi file:///path_to/auto.pac
如何切换回直连状态? 新增一个直连的 direct.pac
sudo networksetup -setautoproxyurl Wi-Fi file:///path_to/direct.pac
如何切换到全局状态? 新增一个 global.pac
sudo networksetup -setautoproxyurl Wi-Fi file:///path_to/global.pac

PHP 出来了应该尝尝鲜, 结果编译没问题, 安装的时候报了如下错误

cp -pR -f phar.phar /usr/local/php7/bin/phar
cp: cannot stat 'phar.phar': No such file or directory
make: *** [install-pharcmd] Error 1

解决方法很简单:

find . -name 'phar.phar'

找到 phar.phar 文件, 移动或者复制到安装指令执行的目录下就行了.

最后附上, 完成后的执行指令:

php5vsphp7

git config --global alias.co checkout
git config --global alias.ci commit
git config --global alias.st status
git config --global alias.br branch
git config --global alias.dci "svn dcommit"
git config --global alias.up "svn rebase"

本文为 虚伪的灵魂 版权所有, 禁止任何商业网站转载, 个人博客转载请于文章起始位置标明 “转载自 使用 strace 测试 Yii 2, Laravel 5, Phalcon 框架性能 – 虚伪的灵魂“.

一. 前言

最近在使用 Laravel, 公司项目上线后, 性能表现不尽如人意, 因为这样的情况, 才促使我去做这样一件测试框架性能的事情. 在朋友的提醒下, 我开始鼓捣起了 strace. strace 是用来追踪进程执行过程中对硬件操作(比如硬盘)时产生的系统调用和所接收的信号的. 本文中所用到的参数很简单, 就是 -c . strace -c 用来统计 php-fpm 在整个执行过程中的各种系统命令的调用数量以及耗时情况. 这已经能在很大程度上判别出一个框架的性能了.

二. 测试设计

  1. 测试对象: 原生PHP, Yii 2, Laravel 5.1 以及 Phalcon 2.
  2. 测试内容1: 测试对象以最快方式输出 “Hello, XXX”, 为了避免初始化的问题, 从第二次起开启 strace 性能追踪, 为避免单次误差, 所以性能追踪连续统计10次.
  3. 测试内容2: 在开启 Zend OPCache 的情况下, 再次完成上述测试, 以理解 OPCache 带来的性能提升, 但是OPCache 是存在内存限制的, 因此每次测试前都会重启 PHP-FPM 进程.

三. 测试代码

a. 原生PHP

<?php
echo 'Hello, World!';

b. Yii 2
新装好 Yii 2, 建立项目后直接修改默认控制器SiteController代码:

<?php

namespace app\controllers;

use Yii;
use yii\filters\AccessControl;
use yii\web\Controller;
use yii\filters\VerbFilter;
use app\models\LoginForm;
use app\models\ContactForm;

class SiteController extends Controller {

    public function actionIndex() {
        return 'Hello, Yii 2!';
    }

}

c. Laravel 5.1
新装好 Laravel 5.1 后, 直接修改 routes.php 文件

<?php

Route::get('/', function () {
    return 'Hello, Laravel!';
});

d. Phalcon 2.
入口脚本

<?php

use Phalcon\Loader;
use Phalcon\Mvc\View;
use Phalcon\Mvc\Url as UrlProvider;
use Phalcon\Mvc\Application;
use Phalcon\DI\FactoryDefault;

try {
    $loader = new Loader();
    $loader->registerDirs(array(
        '../app/controllers/',
        '../app/models/'
    ))->register();
    $di = new FactoryDefault();
    $di->set('view', function(){
        $view = new View();
        $view->setViewsDir('../app/views/');
        return $view;
    });
    $di->set('url', function(){
        $url = new UrlProvider();
        $url->setBaseUri('/tutorial/');
        return $url;
    });
    $application = new Application($di);
    echo $application->handle()->getContent();
} catch(\Exception $e) {
     echo "PhalconException: ", $e->getMessage();
}

默认控制器 IndexController:

<?php

use Phalcon\Mvc\Controller;

class IndexController extends Controller {

    public function indexAction() {
        echo 'Helle, Phalcon!';
    }

}

四. 第一轮测试, 无 Zend OPCache

a. 原生测试结果:

origin

b. Yii 2 测试结果:

yii

C. Laravel 测试结果:

Laravel 第一轮第1次, 直接执行:

laravel

Laravel 第一轮第2次, 在执行过 composer dumpautoload –optimize 后:

laravel2

Laravel 第一轮第3次, 在执行过 php artisan optimize –force 后:

laravel3

D. Phalcon 测试结果:
phalcon2

五. 第一轮试验总结:

  1. 原生还是快的
  2. Laravel 没做优化速度简直感人
  3. Laravel 做完优化速度提升简直感人(自己体会两个感人
  4. 优化过的 Laravel 居然比 Yii 2 跑的快…颠覆了我的认知
  5. Phalcon 2 毫无悬念的在性能上完爆了 Yii 2 和 Laravel. 完全不通的数量级啊.
  6. 另外需要注意的是, 结果是执行10次总的统计数量.

六. 第二轮测试, 有 Zend OPCache.

a. 原生测试结果:

origin

b. Yii 2 测试结果:

yii

C. Laravel 测试结果:

laravel

D. Phalcon 测试结果:

phalcon

七. 第二轮试验总结:

  1. 原生还是快.
  2. Yii 2 性能上胜过了 Laravel.
  3. Phalcon 2 再次毫无悬念的在性能上完爆了 Yii 2 和 Laravel.

八. 试验总结:

  1. 未做 artisan optimize 的 Laravel 性能很差.
  2. OPCache 后的 Yii 2 性能才能胜过 Laravel.
  3. Phalcon 2 性能刚刚的毕竟是扩展级的.
  4. 只要有 PHP 文件就有, OPCache 都有优化的空间(好大一句废话).

九. 测试的不足之处

strace 只能追踪到进程针对硬件的调用, 程序内部的运算对CPU的占用及消耗, 并不能很好的体现出现出来. 比如框架本身存在如果比较大的运算量, 比如正则运算, 并不能很好的体现出来.

十. 思考

  1. Composer 在提供了便利安装依赖的同时是不是增加了性能的负担呢?
  2. Composer 依赖少的时候可能性能并不明显, 而依赖多的时候呢?

一. 安装

1. 下载扩展包

Pecl::Package::Solr 下载最新稳定版扩展包并解包

2. 安装基础库

安装 libcurl devel 文件:
sudo apt-get install libcurl4-gnutls-dev

安装 libxml2 devel 文件:
sudo apt-get install libxml2-dev

3. 编译安装扩展
phpize
./configure
make
sudo make install

4. 添加PHP 扩展配置
extension=solr.so

二. 使用

1. 启动实例

参考 SOLR 的安装使用 一文启动测试实例

2. 在实例中查询

<?php
$options = [
    'hostname' => '127.0.0.1',
    'wt' => 'json',
    'path' => 'solr/gettingstarted_shard1_replica1',
];
$client = new SolrClient($options);

$query = new SolrQuery;
$query->setQuery('lucene');
$query->addField('id');
$query->addField('name');
$query->addField('title');

$resp = $client->query($query);
$r = $resp->getResponse();

var_dump($r);

上面的代码中, 如果不清楚 SolrClient 的 $options 可以使用

$client->getOptions();

获取完整的参数, 然后尝试设置.

3. 添加文档到 Solr 中

<?php
$options = [
    'hostname' => '127.0.0.1',
    'wt' => 'json',
    'path' => 'solr/gettingstarted_shard1_replica1',
];
$client = new SolrClient($options);

$doc = new SolrInputDocument();
$doc->addField('id', 'solr.xwsoul.com');
$doc->addField('title', '虚伪的灵魂');
$doc->addField('description', '人人都是戴着面具而活, 我却连灵魂都是虚伪的.');
$doc->addField('tags', '技术');
$doc->addField('tags', 'Solr');
$response = $client->addDocument($doc);
$client->commit();

$query = new SolrQuery;
$query->setQuery('虚伪 灵魂');
$query->addField('id');
$query->addField('title');
$query->addField('description');
$query->addField('tags');

$resp = $client->query($query);
$r = $resp->getResponse();

var_dump($r);

至此, 我们已经可以简单的通过 PHP 操作 Solr 了.

1. 安装 JDK

我用的Ubuntu 装的 Oracle-java-8

2. 下载最新版的 Solr

Apache Solr 下载最新版并解包, 写文章的时候当前最新版本为5.2.1.

3. 快速启动

1. 启动测试实例
bin/solr start -e cloud -noprompt
启动后, 通过在浏览器中打开 http://localhost:8983/solr/ 访问管理UI.

2. 建立索引
bin/post -c gettingstarted docs/
上述命令建立了 docs/ 目录下的富文件(rich file)内容的索引

3. 开始查询
点击 1 中打开的页面左侧的 Select Core, 选择任意分片, 点击 Query 后选择 Excute Query 即可开始查询.

参考文档: http://lucene.apache.org/solr/quickstart.html

默认情况下 Laravel 会输出 token 等 Cookie.

而在默写情况下, 我们必须禁用这种输出, 比如使用了 ng 的缓存来缓存该页面, 这时候我们就需要禁用 Cookie 了.

在 Laravel 4 中我们可以使用如下代码解决:

<?php
Config::set('session.driver', 'array');

而在 Laravel 5 中, 我们就会遇到这样的错误:

Undefined index: _sf2_meta

经过一番搜索, 在L5中应该使用以下方式:

<?php
Session::setDefaultDriver(null);

已经用了一段时间的 Laravel 了, 已经有点脑残粉的倾向了, 哈哈哈
再来谈谈 Laravel 松散设计的好处吧, 今天做用户登陆真的给我爽到了.

比如 Laravel 里的登录可以通过 Auth::attempt() 实现:

1. 如果你使用的加密方法与 Laravel 默认的不一样怎么办?

1) 写个加密器, 实现 Illuminate\Hashing\HasherInterface 接口的 make(实现加密), check(加密校验), needsRehash(是否重新生成) 三个方法.

2) 写个 Service Provider, 继承 Illuminate\Support\ServiceProvider, 用于注册服务.

3) 修改配置 config -> app.php -> providers 替换 Illuminate\Hashing\HashServiceProvider 为你的 HashServiceProvider.

2. 登陆完成 默认 session 里只存了 user 的 id.
获取用户的信息怎么办?

a. 使用 Auth::user()->xxx, Laravel 会默认帮你到数据库里获取.

如果不想查询数据库, 只想从 session 中获取怎么办? 通过监听事件解决:

<?php
//listen auth login action
Event::listen('auth.login', function() {
    $user = Auth::user();
    Session::put('name', $user->name);
    Session::put('email', $user->email);
});
//listen auth logout action
Event::listen('auth.logout', function() {
    Session::clear();
});

Laravel 在执行登录和登出的时候, 已经触发过登录和登出事件了.

诸如上述的设计, 有什么好处? 好处太明显了, 我只要关注我需要改动的地方就可以了, 其他方面框架都帮你解决了.这样可以实现代码的最大化公用.

再说回来, 如果框架代码本身耦合度太高的话, 实现这些东西比较麻烦, 因为逻辑和业务分离太麻烦, 造成的问题是, 很多情况下如果你要修改代码可能需要重写整个方法, 同时还得在方法中重载父类的方法.

今天尝试使用了 Laravel 的 redis 结果报了如下错误.

Non-static method Redis::xxx() cannot be called statically, assuming $this from incompatible context

因为自己一直在用 Redis 很容易就想到了和既有的 Redis 扩展冲突了, 如果想用 Laravel 自带的 Redis 可以是使用, 如下代码:

use Illuminate\Support\Facades\Redis as Redis;