前言
归功于php相对宽松的语法特性,可以说每个phper都有着自己与他人完全不同的代码风格。同样写代码如何在实现功能的同时又能不失优雅的拉高自身的逼格,当然这也得按照代码规范的基本法,以下就分享音风编码这几年在php方面的一些代码技巧,希望能对你姿势水平的提升有所帮助~
技巧
1. 妙用“逻辑短路”,精炼代码。
// 优化前
$round++;
if($round % 1000){
sleep(1);
}
// 优化后
(++$round) && $round % 1000 || sleep(1);
2. 尽量避免 if 多重嵌套。
// 优化前 if 多重嵌套
if(isset($map[$row['apid']])){
// if...more
if($workflow_writer->query($sql)){
exit('wtf? update workflow_event error!');
}
}
// 优化后
if(!isset($map[$row['apid']])){
// handling...
return
}
if($workflow_writer->query($sql)){
exit('wtf? update workflow_event error!');
}
// 究极优化...
$map[$row['apid']] && !$workflow_writer->query($sql) && exit('wtf update workflow_event error!');
3. 避免产生超大数组,擅用yield实现迭代器,节省大量内存
// 优化前
function get_bigger_array($nums){
$arr = [];
for($i=0;$i<$nums;$i++){
$arr[] = $i;
}
return $arr;
}
echo 'memory used: '.memory_get_usage().PHP_EOL;
$data = get_bigger_array(10000000);
echo 'memory used: '.memory_get_usage().PHP_EOL;
// 优化后
function get_bigger_array_yield($nums){
for($i=0;$i<$nums;$i++){
yield $i;
}
}
echo 'memory used: '.memory_get_usage().PHP_EOL;
$data = get_bigger_array_yield(10000000);
echo 'memory used: '.memory_get_usage().PHP_EOL;
var_dump($data->current());
进阶
上面代码片段讲到了如何用yield关键字返回生成器实现迭代。但是yield的应用场景还远远不止如此,接下来我们试作封装迭代器的send()使得生成器的迭代更加自如方便,这样的封装我们称之为调度器。有了Generator(生成器)、Task(任务)、Scheduler(调度器)三要素才能真正实现协程。了解了yield的工作机制,你才能更好的了解什么是PHP的协程。
注意:协程不是并发多线程,而是一种在用户态程序自身的管理调度协作方式!
use Jamlee\Coroutine\Scheduler;
use Jamlee\Coroutine\SystemCall;
require '../vendor/autoload.php';
function loop($max){
$tid = yield SystemCall::getTaskId();
for($i=0; $i<$max; $i++){
printf('loop[%d]:$i = %d'.PHP_EOL, $tid, $i);
yield;
}
}
$scheduler = new Scheduler;
$scheduler->NewTask(loop(10));
$scheduler->NewTask(loop(10));
$scheduler->run();
class Task {
protected $taskId;
protected $coroutine;
protected $sendValue = null;
protected $beforeFirstYield = true;
public function __construct($taskId, Generator $coroutine) {
$this->taskId = $taskId;
$this->coroutine = $coroutine;
}
public function getTaskId() {
return $this->taskId;
}
public function setSendValue($sendValue) {
$this->sendValue = $sendValue;
}
public function run() {
if ($this->beforeFirstYield) {
$this->beforeFirstYield = false;
return $this->coroutine->current();
} else {
$retval = $this->coroutine->send($this->sendValue);
$this->sendValue = null;
return $retval;
}
}
public function isFinished() {
return !$this->coroutine->valid();
}
}
class Scheduler {
protected $maxTaskId = 0;
protected $taskMap = []; // taskId => task
protected $taskQueue;
public function __construct() {
$this->taskQueue = new SplQueue();
}
public function newTask(Generator $coroutine) {
$tid = ++$this->maxTaskId;
$task = new Task($tid, $coroutine);
$this->taskMap[$tid] = $task;
$this->schedule($task);
return $tid;
}
public function schedule(Task $task) {
$this->taskQueue->enqueue($task);
}
public function run() {
while (!$this->taskQueue->isEmpty()) {
$task = $this->taskQueue->dequeue();
$task->run();
if ($task->isFinished()) {
unset($this->taskMap[$task->getTaskId()]);
} else {
$this->schedule($task);
}
}
}
}
class SystemCall {
protected $callback;
public function __construct(callable $callback) {
$this->callback = $callback;
}
public function __invoke(Task $task, Scheduler $scheduler) {
$callback = $this->callback;
return $callback($task, $scheduler);
}
public static function getTaskId(){
return new self(function (Task $task, Scheduler $scheduler) {
$task->setSendValue($task->getTaskId());
$scheduler->schedule($task);
});
}
}
view source code by Github
Comments | NOTHING (这是个静态化页面,评论后要等CDN刷新啦~)