项目中使用到了predis库,现在项目有需求需要使用多个LUA脚本,那么这些文件(.php)改放在什么地方合适呢?
放在third_party/predis111/scr/MyScript目录下是最方便的,但是不合适!
原因:predis111是库sdk ,放在他下面就是改变了sdk, sdk变得不干净了,后期sdk升级自己的脚本就被覆盖了,很危险!
放在libraries 目录下相对合适,像PHPEXCEL 如果大量使用,为了更好组织文件(也许自己写了子类,父类,抽象类)这样的话更需要引入命名空间,自动加载。
组织结构如下:
要使调用时能找到对应的类文件就要使用类自动加载和命名空间了。
Predis.php代码如下:
注意,两个autoload.php 的require包含,第一个目的是为了能自动找到sdk中的类, 第二个目的是为了能自动找到MyscriptLiang下的类文件。
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
require APPPATH.'third_party/predis111/autoload.php';
require APPPATH."libraries/predis/autoload.php";
class Predis{
private $_redis = null;
public function __construct(){
$CI = &get_instance();
$CI ->config->load('predis',TRUE);
$predis_config = $CI ->config->item('predis','predis');
$host = isset($predis_config['default']['host']) ? $predis_config['default']['host'] : null;
$port = isset($predis_config['default']['port']) ? $predis_config['default']['port'] : null;
if(empty($host) || empty($port)){
exit('predis config error');
}
$this->_redis = new Predis\Client(array(
'host'=> $host,
'port' => $port
));
try{
$this->_redis->connect();
}catch(Predis\Connection\ConnectionException $e){
echo 'Predis connect redis-server has exception! Message:'.$e->getMessage();
exit();
}
}
public function __call($name,$args){
$callback = array($this->_redis,$name);
return call_user_func_array($callback,$args);
}
}
自定的autoload.php 代码如下:
注意:定义命名空间
<?php
/**
* Created by PhpStorm.
* User: liang
* Date: 2018/3/23
* Time: 下午11:19
*/
namespace lib\Predis;
spl_autoload_register(function($className){
// echo __NAMESPACE__;
echo 'CLASS:',$className, "<br/>";
//className : 如:lib\Predis\MyscriptLiang\Sumscores
if(0 === strpos($className, __NAMESPACE__)) {
//echo substr($className, strlen(__NAMESPACE__)),"<br/>"; // \MyscriptLiang\Sumscores
$parts = explode('\\', substr($className, strlen(__NAMESPACE__.'\\')));
echo "<pre>";
var_dump($parts); //PATH:/mnt/hgfs/work_www/blog/application/libraries/predis/MyscriptLiang/Sumscores.php
echo "</pre>";
// array(2) {
// [0]=>
// string(13) "MyscriptLiang"
// [1]=>
// string(9) "Sumscores"
//}
$filepath = __DIR__.DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR, $parts).'.php';
echo "PATH:";
echo $filepath;
echo "<br/>";
if (is_file($filepath)) {
require $filepath;
}
}
},true,false);
脚本Sumscores.php 中注意定义自己的命名空间;想使用sdk 中类,就要use引用sdk中的命名空间,代码如下:
<?php
/**
* Created by PhpStorm.
* User: liang
* Date: 2018/3/19
* Time: 上午11:15
*/
namespace lib\Predis\MyscriptLiang;
use Predis\Command\ScriptCommand;
class Sumscores extends ScriptCommand {
public function getKeysCount()
{
// Tell Predis to use all the arguments but the last one as arguments
// for KEYS. The last one will be used to populate ARGV.
return -1;
}
/**
* @return string
* 注意ipairs 和pairs区别!
*/
public function getScript()
{
return <<<LUA
local sum = 0
local users = redis.call('mget',unpack(KEYS))
for _, user in ipairs(users) do
local courses = cjson.decode(user).courses
for c, score in pairs(courses) do
sum = sum + score +3
end
end
return sum
LUA;
}
}
libraries中自己类组织好了,下面看看控制器中怎么使用这些类?Script.php 代码如下:
public function test_sum(){
$this->load->library('predis');
$this->predis->getProfile()->defineCommand('sumscores','lib\Predis\MyscriptLiang\\'.'Sumscores'); // \挨着' 所以需要转译
$bob = new stdClass();
$bob->name = 'bob';
$bob->courses = new stdClass();
$bob->courses->数学 = 90;
$bob->courses->语文 = 70;
$jeff = new stdClass();
$jeff->name = 'jeff';
$jeff->courses = new stdClass();
$jeff->courses->数学 = 80;
$jeff->courses->语文 = 60;
$bob = array(
'name'=>'bob',
'courses'=>array(
'math'=> 90,
'yuwen'=> 100
)
);
$jeff = array(
'name'=>'jeff',
'courses'=>array(
'math'=> 80,
'yuwen'=> 60
)
);
$this->predis->set('script:user:1',json_encode($bob));
$this->predis->set('script:user:2',json_encode($jeff));
$sum = $this->predis->sumscores('script:user:1','script:user:2','argv');
echo 'sum:';
var_dump($sum);
}