CimpleBlog

PHP归并排序

<?php

function sortArr($arr) {
    if (count($arr) < 2) {
        return $arr;
    }
    $mid = count($arr) / 2;
    $arr1 = array_slice($arr, 0, $mid);
    $arr2 = array_slice($arr, $mid, count($arr));
    $arr1 = sortArr($arr1);
    $arr2 = sortArr($arr2);

    return mergeArr($arr1, $arr2);
}

function mergeArr($arr1, $arr2) {

    if (!is_array($arr1)) {
        $arr1[] = $arr1;
    }
    if (!is_array($arr2)) {
        $arr2[] = $arr2;
    }

    $i =0;
    $j = 0;
    $arr1Length = count($arr1);
    $arr2Length = count($arr2);
    $returnArr = [];
    while($i < $arr1Length && $j < $arr2Length) {
        if($arr1[$i] > $arr2[$j]) {
            $returnArr[] = $arr2[$j];
            $j++;
        } else {
            $returnArr[] = $arr1[$i];
            $i++;
        }
    }
    for($tmp = $i; $tmp < $arr1Length; $tmp++) {
        $returnArr[] = $arr1[$tmp];
    }
    for($tmp = $j; $tmp < $arr2Length; $tmp++) {
        $returnArr[] = $arr2[$tmp];
    }
    return $returnArr;
}

$arr = [1,3,2,5,7,9,3,1];


$sortableArr = sortArr($arr);

foreach ($sortableArr as $a) {
    print_r($a . "\n");
}


说实话,算法这东西,挺好玩的,以前还搞过快排,但是忘却了,今天这个归并排序应该很难忘记了,毕竟理解起来要比快排好得多,但是快排回来后面补充


Redis zSets 数据类型不一致踏坑记

redis

今天在公司写代码的时候,遇到了一个大问题,简单说一下场景,有两处使用了一个 zSets,一处是从网页获取数据,放到zSets里面;另一处是从数据库获取数据放到 zSets 里面。在后期做清除数据操作的时候,发现了数据清除的不完全,后来仔细的检查了一下。发现数据重复。

仔细测试了好一会儿之后,才发现了问题坐在,就是当score相同的时候,相同的value会覆盖数据,这里的value相同,并不仅仅是值相同,而且数据类型也应该一致才会覆盖。否则就会产生score相同的两条数据。

这个问题是个大坑,记录下来,以后一定要记得


PHP 自动加载

做编程3年了,几乎每年一个转型 (java -> android(web app) -> php),这个节奏太不舒服了。想深入了解什么的时候,总是无奈的转型。现在自己也算是彻底的稳定下来了。可以安心的研究 php 了。php 也做了一年多了,一直在用框架,也就是最近几个月吧,认识到了自己的不足之处,开始逐步研究一些细节方面的东西。

这个博客使用 laravel 弄的,里面很多的细节都是在以前的 java 的时候接触过,但是以前弄 java 的时候就没有太细致的研究。现在也就顺道一起弥补回来。

今天要写的是自动加载, php 中如果想要加载一个类的话,一般采用 require 或者 include 但是呢,自动引入了命名空间以后,类名加上命名空间超级长,然后每个文件开头一排 require 外加一排 use 这个文件无疑太长,而且如果某一次忘记了引入文件,如果项目过大,那么结果就是两个字爆炸 boom shakalaka。排查起来超级麻烦。

所以,就有了自动加载,以前用自动加载都是使用 *__autoload* 但是这个方法有一个bug,就是只能使用一次。这样造成的问题就是如果我们有多种状态的引用的话,就会产生很长的代码,这是我们所不想见到的。于是就有了 *spl_autoload_register* 其实,从文档上来看他就是 autoload 的一种实现,但是区别是,这个方法可以执行多次。但是以我这一段看代码来看,其实也就是使用了一次。但是安全第一,而且为了标准还是使用 *spl_autoload_register* 。

上面说了一大堆没用,其实有用的就是一个方法 spl_autoload_register ,具体看文档: [http://php.net/manual/zh/function.autoload.php]。

下面进入正题,开始我们的自动加载吧。我直接上代码了:

<?php

use Test32\Test;

spl_autoload_register(function ($class) {
    $path = str_replace('\\', DIRECTORY_SEPARATOR, $class);
    $path .= '.php';
    if (file_exists($path)) {
        require_once ($path);
    } else {
        throw new Exception('Class not exist!');
    }
}, true);

$test = new Test();

$test->sayHello();

现在来解释一下:这个方法会接受三个参数,第一个是一个回掉函数,后面两个是bool类型的参数。后面两个很少使用,所以我们就着重说一下第一个回掉函数,这个函数有一个参数是一个包含命名空间的类名,也就是我们use的那一个部分的名称,我们在这里是使用层次文件夹的方式,构造的目录和文件结构的。所以,在我们收到名称之后,先转换为路径在加上 .php 的文件名后缀,判断一下文件是否存在。如果存在就 require 进去。如果不存在就抛出一个异常,告知class不存在。这样要简单的自动加载器就完成了。

过一段会写composer的各种加载方式。今天就到这里了。后续还会继续写反射相关的东西。然后我自己的大轮子也会以这个自动加载作为一切的基础。逐步完善轮子


Mysql 批量更新多行笔记

今天在公司写代码的时候使用到了 mysql 的批量更新,但是呢,自己之前对其了解的果然不够多啊。所以,回家以后赶紧查查,做好笔记,让自己有更深的记忆。以及更多的了解。

首先我们构造好了一个测试表,如下图

数据库示意图

Read more

max nginx相关备忘 以及 主机相关设置

Docroot is: /usr/local/var/www

The default port has been set in /usr/local/etc/nginx/nginx.conf to 8080 so that
nginx can run without sudo.

nginx will load all files in /usr/local/etc/nginx/servers/.

To have launchd start nginx now and restart at login:
  brew services start nginx
Or, if you don't want/need a background service you can just run:
  nginx

上面的一些都是安装后的提示项,帮助我以后找回东西的时候用的。

安装好以后配置一下虚拟主机。只要吧 fastcgi_params 中的/script 替换为$document_root 就 ok 了。 然后启动 php-fpm

sudo /usr/local/sbin/php70-fpm start

最后以及最坑的一步,别忘了 storage 的权限设置

chmod -R 777 storage

至此在本地搭建环境也就 ok 了,php 和 mysql 直接用 homebrew 安装即可,php 相关配置可以从 phpinfo 查到,mysql 的配置,待我学习后补充


Laravel5.1 自定义分页样式的探索

题外话:查东西真心不能用百度,得用google,如果提前查google的话,也许这篇文章就不是自己写的了,可能就是转载的了,不过自己搞出来的东西记忆比较深刻,也是不错的,哈哈。下面进入正文。

话说,自己在写这个博客的时候要弄到分页,按照文档 rander() 出来以后居然是bootstrap的样式,这是什么鬼。百度了一圈之后,很多文章都是说改源码,这一定不科学。对于框架来说一定是可以扩展的,所以,开始爬源码吧。当我们调用 paginate() 方法的时候返回的是一个 \Illuminate\Contracts\Pagination\LengthAwarePaginator 实例,不过这个东西是个接口,肯定会有实现类的,所以,继续查,发现了 Illuminate\Pagination\LengthAwarePaginator 这个类实现了上边的接口,好吧,就决定是你了,皮卡丘。

继续看 render 方法

    /**
     * Render the paginator using the given presenter.
     *
     * @param  \Illuminate\Contracts\Pagination\Presenter|null  $presenter
     * @return string
     */
    public function render(Presenter $presenter = null)
    {
        if (is_null($presenter) && static::$presenterResolver) {
            $presenter = call_user_func(static::$presenterResolver, $this);
        }

        $presenter = $presenter ?: new BootstrapThreePresenter($this);

        return $presenter->render();
    }

上面的最终返回了一个BootstrapThreePresenter,进去看一下,发现就是渲染分页样式的,所以说,我们只要自己定义一个分页样式类,并且传入render方法,就可以了。

下面我们自定义一个 AmazeuiThreePresenter 类,继承自BootstrapThreePresenter,因为这样就可以节省好多方法了。 下面上最终代码

<?php

namespace App;

/**
 * Created by PhpStorm.
 * User: Chris
 * Date: 2016/8/21
 * Time: 20:34.
 */
class AmazeuiThreePresenter extends \Illuminate\Pagination\BootstrapThreePresenter
{
    public function render()
    {
        if ($this->hasPages()) {
            return sprintf(
                '<ul class="am-pagination am-pagination-centered">%s %s %s</ul>',
                $this->getPreviousButton(),
                $this->getLinks(),
                $this->getNextButton()
            );
        }

        return '';
    }

    /**
     * Get HTML wrapper for disabled text.
     *
     * @param string $text
     *
     * @return string
     */
    protected function getDisabledTextWrapper($text)
    {
        return '<li class="am-disabled"><span>'.$text.'</span></li>';
    }

    /**
     * Get HTML wrapper for active text.
     *
     * @param string $text
     *
     * @return string
     */
    protected function getActivePageWrapper($text)
    {
        return '<li class="am-active"><span>'.$text.'</span></li>';
    }
}

这样就ok了,好多方法 BootstrapThreePresenter 都实现出来了,所以我们只要修改一些对于我们样式相关的就可以了。

最后,我们在模板render的时候传入我们自定义的就可以了。如下

 {!! $articles->render(new \App\AmazeuiThreePresenter($articles)) !!}

最后的最后,再写这个文章的时候,发现了 static::$presenterResolver 这个东西,是不是还有更简单的方法呢,待我研究研究


PHP匿名函数以及call_user_func的思考

配图依然与主题无关,仅仅是我个人喜欢而已,今天要说的是关于 call_user_func 的一些理解。

以前对于闭包和匿名函数的理解不是太好。所以,今天在 phphub 提问的时候犯了一个比较二的错误,趁着晚上回家赶紧总结一下,增强自己的记忆。

话说以前对于闭包或者匿名函数都是自己写自己调用,所以没有出现过什么问题,但是前几天在弄 laravel 分页的时候,发现里面有一个 $presenter 自己知道这个可能会让我的代码更简洁,但是我却不知道如何调用,在 phphub 提问的时候有人告诉了我怎么使用,但是我却对参数列表比较迷惑,是如何获取参数列表的。今天终于有人告诉了我,我才发现对于 php 的一些函数理解的并不是很到位。于是乎赶紧翻阅 php 文档,把 call_user_func 再次理解一下。参见: (http://php.net/manual/zh/function.call-user-func.php) 。

文档说的比较明白,第一个参数是方法名称,余下的参数就是调用方法的参数列表了。

    public function render(Presenter $presenter = null)
    {
        if (is_null($presenter) && static::$presenterResolver) {
            $presenter = call_user_func(static::$presenterResolver, $this);
        }

        $presenter = $presenter ?: new BootstrapThreePresenter($this);

        return $presenter->render();
    }

所以,这个 render 方法里面就比较容易理解了,当我们传入的 $presenter 为空的时候,并且 static::$presenterResolver ($static是延迟绑定,这个也可以在文档里面找到)已经赋值的时候,就会执行 if 代码段里面的内容了。在我的代码中主要应用的是 LengthAwarePaginator 类里面的相关方法(其实还有一个 Paginator 类,这个类是用在那个 simple 的简单分页中的),在这里面我并没有找到为 $presenter 赋值的方法,所以我们去他们的父类 AbstractPaginator 中寻找,果然里面有为 $presenter 赋值的方法。

    /**
     * Set the default Presenter resolver.
     *
     * @param  \Closure  $resolver
     * @return void
     */
    public static function presenter(Closure $resolver)
    {
        static::$presenterResolver = $resolver;
    }

可以看到这里面接受的参数是一个闭包或者说匿名函数(这两个东西我还得理解一下)。

至此,一些就很通顺了。我们传入的匿名函数的参数是 AbstractPaginator 的具体实现类,里面实现了分页相关渲染的方法。

所以,我们最终在provider里面待用相关的设置方法

        // 设定分页主题
        LengthAwarePaginator::presenter(function ($paginator) {
            return new AmazeuiThreePresenter($paginator);
        });

这样我们在模板里面直接调用 render 即可,也不用时刻记得传入参数了。


关于 laravel 服务提供者的思考

配图与文章无关,仅仅是最近十分喜欢这个图片而已

这个博客写完之后,一直在看 laravel 的文档,其实每次都是纠结在服务提供者上面,其实以前在弄 java 的时候就对什么 IOC\DI 什么的理解的不够深刻。我觉得现在我终于可以说说我对于这一块的理解了。

哦对了,还想说一些东西,就是单独去理解一个问题那是不好的,而是要综合现有的东西去结合理解。比如说服务提供者的这个问题吧,我就就在在了。含义我理解了,但是在 laravel 框架里面结合的上面,昨天回去看了看源码,并且刚才又看了文档,觉得自己明白一些了。

其实 IOC\DI 这个东西,原本就是个独立的东西,至于在框架中如何实现则是另一个问题了(这里所说的实现是指以来的配置项,长久以来我就在这方面纠结)。

IOC\DI 就是什么依赖注入啊,控制反转啊什么。简单点说就是解耦,可替换,让我们的程序更加的灵活。

我说纠结的就是替换的部分,就是如何去配置那些以来以及加载。这个从代码以及文档理解了一些,更多的东西。留在下一篇来弄