CimpleBlog

deepin 添加 phpstorm 快捷方式到 application 目录

首先创建 Phpstorm.desktop 文件,并把下面的代码输入

[Desktop Entry]
Categories=Development;
Comment[zh_CN]=
Comment=
Exec=/opt/phpstorm/bin/phpstorm.sh
GenericName[zh_CN]=IDE
GenericName=IDE
Icon=/opt/phpstorm/bin/webide.png
Name[zh_CN]=phpStorm           
Name=phpStorm       
Path=
StartupNotify=true
Terminal=false
Type=Application
X-DBUS-ServiceName=
X-DBUS-StartupType=
X-KDE-SubstituteUID=false
X-KDE-Username=Learn Programming

说明一下 Exec 是执行文件的路径,Icon 是图标的路径,Categories 是分类,这个根据系统来就可以了

然后执行下面两行代码

sudo mv Phpstorm.desktop /usr/share/applications/
sudo chmod +x Phpstorm.desktop

这样就 ok 了,在 application 目录里面就会有 phpstorm了,就这么简单,这个适用于 debain 系列,其他应用也是这样添加就ok了


通过快排和归并排序思考分治法

话说以前看过很多算法相关的书,大部分讲的都很模糊,然后直接上代码,当时看似理解了,可是时间一长就忘光光了,以前看书学习的都是如何去做,而自己也没有深入的思考过为何这么做,单纯的就是背下来那种。当学习到一定程度之后,发现基础知识还是非常重要的。

今天要说的就是分治法,什么是分治法,就是分而治之,先把把大的问题分解为小一些的问题。逐步把小问题解决了,在把这些解决的小问题合并了就把大问题解决了,这就是我所理解的分治法。

我们在看算法排序相关的时候,都会有并归排序和快速排序,这两个方法都是用分治法解决的,只不过解决的方案不一样。下面是我用 php 实现的代码,大家可以先看下,然后我会在代码后面对两种方式做说明。

/**
 * 归并排序
 * @param $arr
 * @return array
 */
function mergeSort($arr)
{
    $arrCount = count($arr);
    if ($arrCount < 2) {
        return $arr;
    }
    $mid = ceil($arrCount / 2); // 向上取整一下
    $leftArr = array_slice($arr, 0, $mid);
    $rightArr = array_slice($arr, $mid, $arrCount - $mid);
    return mergeArr(mergeSort($leftArr), mergeSort($rightArr));
}

/**
 * 最终合并数组的方法
 * @param $leftArr
 * @param $rightArr
 * @return array
 */
function mergeArr($leftArr, $rightArr)
{
    $i = 0;
    $j = 0;
    $returnArr = [];
    while ($i < count($leftArr) && $j < count($rightArr)) {
        if ($leftArr[$i] < $rightArr[$j]) {
            $returnArr[] = $leftArr[$i];
            $i++;
        } else if ($leftArr[$i] > $rightArr[$j]) {
            $returnArr[] = $rightArr[$j];
            $j++;
        } else {
            $returnArr[] = $leftArr[$i];
            $returnArr[] = $rightArr[$j];
            $i++;
            $j++;
        }
    }
    for ($temp = $i; $temp < count($leftArr); $temp++) {
        $returnArr[] = $leftArr[$temp];
    }
    for ($temp = $j; $temp < count($rightArr); $temp++) {
        $returnArr[] = $rightArr[$temp];
    }
    return $returnArr;
}

/**
 * 快速排序
 * @param $arr
 * @return array
 */
function quickSort($arr)
{
    if (count($arr) < 2) {
        return $arr;
    }
    $flag = $arr[0];
    $lessArr = [];
    $largeArr = [];
    $flagArr = [];
    $flagArr[] = $flag;

    for ($i = 1; $i < count($arr); $i++) {
        if ($arr[$i] < $flag) {
            $lessArr[] = $arr[$i];
        } else if ($arr[$i] > $flag) {
            $largeArr[] = $arr[$i];
        } else {
            $flagArr[] = $arr[$i];
        }
    }

    return array_merge(quickSort($lessArr), $flagArr, quickSort($largeArr));
}

先来说一下快排,因为快排的代码比较简短。快排的解决方案是,找出一个数字,一般都是采用数组的第一个数字作为标识数字,然后把比这个数字小的放到一个数组里面,在把比这个数字大的放到一个数组里面。这样,我们就已经确定好中间的数字了,然后我们在采用递归的方式分别处理比标志位数字小的数组和比标志位大的数组。 但是在处理递归的时候我们要注意一个点,就是何时终止递归,让其返回,这个点就是当数组的元素个数小于2的时候,因为这个时候已经不需要进行比较了。

好吧,简单吧,其实我们可以用笔在纸上画一画模拟一下流程,就会更加的清晰。

再来说说归并,归并理解起来要比快排麻烦一些,因为并没有那么直观,不直观的原因就是最后一步了,我们从头开始吧。归并排序思想就是把数组折半拆分,然后拆成一个个的小单元,那么多小是小呢,就是上面快排说的终止点,这个终止点就是当数组元素小于2的时候,因为这个时候已经没有办法继续拆分了。拆分后就是合并,那么如何合并呢,这个合并就是我个人认为复杂地方,合并的是偶我们比较每个数组的值,具体的方法看看代码吧,就是利用游标。找出小的来,然后放到结果数组中,这样一次次的合并之后每个小数组就都是有序的,然后在一次次的合并回去,这个归并我觉得看看就好了,实际上就用快排好啦。起码我个人没用过归并在实际项目中。

好吧上面简单的说了一下两个排序的方式,其实我最想说的就是分治法,其实在我刚开始学习算法的时候就是知道了哦,这个排序是利用分治法,那么如何分而治之我却没有深入的了解,在最近看一个老外的算法书的时候忽然灵光一闪,想把这两个方式比较一下,也就有了今天的文章。其实啊,现在再让我说什么事分治法,我也会说把大问题分解成小问题,小问题解决后,合并到大问题上面也就解决了。说了半天还是废话把,再想想上面两个排序拆分的方式,差别就是拆分方式不同,这其实才是我想说的,观看问题的角度不同,解决方案也不同,多看看别人的代码,多思考自己的方案,多学习。才能更灵活,我个人觉得学习算法不是让我们死记硬背应付面试的,而是拓宽了我们的思路,在合适的时候选用合适的方法罢了。

加油吧,新的算法书看了44%了,这周争取搞定,虽然之后200页。


Php依赖注入容器Pimple的笔记

话说许久没有写技术类的笔记了,也该写点东西了,距离上次说 container 已经过去4个月了,期间也一直在学习,但是不知道写点什么好,说实话还是很怀念 14 年下半年,那半年的进步真的很大,那时候自己愿意看东西,也愿意写东西,也许写东西能让自己进步更快吧,所以17年了也应该继续进步了,否则问题大大的啊,下班的时候跟小伙伴聊天,做技术的就应该一直学习,否则就会被拉下很远很远。好了,说了这么多废话,说点正文吧,其实,想写 laravel 的 container 的笔记的,可是,自己看了许久,也没有很好的理解,理解到的部分也是很片面的东西,不过 laravel 的 container 真的很强大,要比今天写的这个强大的多,不过强大的带来的问题,就是可能会慢,毕竟用到了反射,今天这个 Pimple 则相对简单的多了,没有那么多复杂的东西,用起来也很顺手而且比较容易理解,所以今天就用这个做笔记了。

原本想分段做这个的笔记的,后来觉得应该吧知识点拆分开说明,然后再用整体代码在里面做注释的方式来解释这段更好一些,于是乎,准备开整,btw,过几天准备更新一下编辑器,现在这个自己搞得编辑器还是有些简陋的。好吧,进入正文了。

class Container implements \ArrayAccess

这个类实现了 ArrayAccess 接口,ArrayAccess 是个什么东西了,大家首先看一下 PHP 官网的手册 http://php.net/manual/zh/class.arrayaccess.php 好吧,我就简单说一句,就是让对象能够像数组一样操作了。具体需要实现的几个接口,大家看一下手册吧,我觉得我的说明肯定没有手册写得好,我更多理解的东西,会在代码注释中写一下。

public function __construct(array $values = array())
    {
        $this->factories = new \SplObjectStorage();
        $this->protected = new \SplObjectStorage();

        foreach ($values as $key => $value) {
            $this->offsetSet($key, $value);
        }
    }

在构造方法中又出现了 SplObjectStorage 类,那么这个 SplObjectStorage 是个什么东西呢,我们再去看一下手册 http://php.net/manual/zh/class.splobjectstorage.php 这个在手册中可惜翻译的不完全(根本没有翻译),所以我就简单的说说,这个类其实是实现了 Countable , Iterator , Serializable , ArrayAccess 这4个接口,这4个接口大家也可以看一下手册,看完了就知道这个类是干什么的了,我再来拆分说下 Countable 就是让一个类可以用一个计数器, Iterator 就是可以用 foreach 这些去循环,Serializable 就是可以序列化,ArrayAccess 上面说过了就不多说了。其实刚开始很难理解这个类,不过多看看手册,别人的示例代码,自己在多写一些可能就了解了。这个如何理解我也说不太好。大家见谅。

好吧,我觉得是额外知识点的就上面那些,等多的笔记我将在下面的代码注释中说明白,大家可以看看,顺便帮忙指正。

<?php

/*
 * This file is part of Pimple.
 *
 * Copyright (c) 2009 Fabien Potencier
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is furnished
 * to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

namespace Pimple;

/**
 * Container main class.
 *
 * @author  Fabien Potencier
 */
class Container implements \ArrayAccess
{
    private $values = array(); // 存储 value 的数组
    private $factories; // 存储工厂方法的对象
    private $protected; // 存储保护方法的对象
    private $frozen = array(); // 存储冻结的数组,也就是在这个数组里面的 key 的 value 是不可更改的了
    private $raw = array(); // 存储
    private $keys = array(); // 存储 key 的数组

    /**
     * Instantiate the container.
     *
     * Objects and parameters can be passed as argument to the constructor.
     *
     * @param array $values The parameters or objects.
     */
    public function __construct(array $values = array())
    {
        // 构造工厂对象以及保护方法对象
        $this->factories = new \SplObjectStorage();
        $this->protected = new \SplObjectStorage();
        // 把初始化的值存放到现有的里面
        foreach ($values as $key => $value) {
            $this->offsetSet($key, $value);
        }
    }

    /**
     * Sets a parameter or an object.
     *
     * Objects must be defined as Closures.
     *
     * Allowing any PHP callable leads to difficult to debug problems
     * as function names (strings) are callable (creating a function with
     * the same name as an existing parameter would break your container).
     *
     * @param string $id    The unique identifier for the parameter or object
     * @param mixed  $value The value of the parameter or a closure to define an object
     *
     * @throws \RuntimeException Prevent override of a frozen service
     * 设置相关值以及对象
     */
    public function offsetSet($id, $value)
    {
        // 如果这个值被 frozen 了,就不允许更改了
        // 应该是为了保持高效性,会把 get 过的值存储起来,所以就不在调用了也就不允许更改了
        // 其实也可以更改,在下面的方法中说明
        if (isset($this->frozen[$id])) {
            throw new \RuntimeException(sprintf('Cannot override frozen service "%s".', $id));
        }
        // 存储值方法
        $this->values[$id] = $value;
        // 存储 key 的值
        $this->keys[$id] = true;
    }

    /**
     * Gets a parameter or an object.
     *
     * @param string $id The unique identifier for the parameter or object
     *
     * @return mixed The value of the parameter or an object
     *
     * @throws \InvalidArgumentException if the identifier is not defined
     * 获取值得方法
     */
    public function offsetGet($id)
    {
        // 如果没有设置 key 则抛出异常
        if (!isset($this->keys[$id])) {
            throw new \InvalidArgumentException(sprintf('Identifier "%s" is not defined.', $id));
        }

        // 如果 raw 里面已经有了, 或者 values 里面存储对应 key 的值不是个 obj,或者 protected 里面也有对应的值 或者值里面的方法存在,则直接返回,values 数组里面的结果
        if (
            isset($this->raw[$id])
            || !is_object($this->values[$id])
            || isset($this->protected[$this->values[$id]])
            || !method_exists($this->values[$id], '__invoke')
        ) {
            return $this->values[$id];
        }

        // 如果工厂方法里面设置了相关方法则要直接返回
        if (isset($this->factories[$this->values[$id]])) {
            return $this->values[$id]($this);
        }

        // 获取值里面的方法
        $raw = $this->values[$id];
        // 执行上面获取到的方法获取返回值 并且覆盖 values
        $val = $this->values[$id] = $raw($this);
        // 把原始方法存储到 raw 数组里面,用来给 raw 方法调用
        $this->raw[$id] = $raw;
        // 把这个值设置为冻结,不允许将来的更改
        $this->frozen[$id] = true;
        // 返回结果值
        return $val;
    }

    /**
     * Checks if a parameter or an object is set.
     *
     * @param string $id The unique identifier for the parameter or object
     *
     * @return bool
     * 获取 key 是否存在
     */
    public function offsetExists($id)
    {
        return isset($this->keys[$id]);
    }

    /**
     * Unsets a parameter or an object.
     *
     * @param string $id The unique identifier for the parameter or object
     * 删除掉 key
     */
    public function offsetUnset($id)
    {
        // 如果存在则删除相关的值
        if (isset($this->keys[$id])) {
            // 如果存储的是个对象,则删除相关的值
            if (is_object($this->values[$id])) {
                unset($this->factories[$this->values[$id]], $this->protected[$this->values[$id]]);
            }
            // 删除普通数组里面的值
            unset($this->values[$id], $this->frozen[$id], $this->raw[$id], $this->keys[$id]);
        }
    }

    /**
     * Marks a callable as being a factory service.
     *
     * @param callable $callable A service definition to be used as a factory
     *
     * @return callable The passed callable
     *
     * @throws \InvalidArgumentException Service definition has to be a closure of an invokable object
     * 设置工厂方法
     */
    public function factory($callable)
    {
        if (!method_exists($callable, '__invoke')) {
            throw new \InvalidArgumentException('Service definition is not a Closure or invokable object.');
        }

        $this->factories->attach($callable);

        return $callable;
    }

    /**
     * Protects a callable from being interpreted as a service.
     *
     * This is useful when you want to store a callable as a parameter.
     *
     * @param callable $callable A callable to protect from being evaluated
     *
     * @return callable The passed callable
     *
     * @throws \InvalidArgumentException Service definition has to be a closure of an invokable object
     */
    public function protect($callable)
    {
        if (!method_exists($callable, '__invoke')) {
            throw new \InvalidArgumentException('Callable is not a Closure or invokable object.');
        }

        $this->protected->attach($callable);

        return $callable;
    }

    /**
     * Gets a parameter or the closure defining an object.
     *
     * @param string $id The unique identifier for the parameter or object
     *
     * @return mixed The value of the parameter or the closure defining an object
     *
     * @throws \InvalidArgumentException if the identifier is not defined
     * 其实这个就是获取设置的对象或者方法
     */
    public function raw($id)
    {
        if (!isset($this->keys[$id])) {
            throw new \InvalidArgumentException(sprintf('Identifier "%s" is not defined.', $id));
        }
        if (isset($this->raw[$id])) {
            return $this->raw[$id];
        }

        return $this->values[$id];
    }

    /**
     * Extends an object definition.
     *
     * Useful when you want to extend an existing object definition,
     * without necessarily loading that object.
     *
     * @param string   $id       The unique identifier for the object
     * @param callable $callable A service definition to extend the original
     *
     * @return callable The wrapped callable
     *
     * @throws \InvalidArgumentException if the identifier is not defined or not a service definition
     * 修改已经存在的值
     */
    public function extend($id, $callable)
    {
        if (!isset($this->keys[$id])) {
            throw new \InvalidArgumentException(sprintf('Identifier "%s" is not defined.', $id));
        }

        if (!is_object($this->values[$id]) || !method_exists($this->values[$id], '__invoke')) {
            throw new \InvalidArgumentException(sprintf('Identifier "%s" does not contain an object definition.', $id));
        }

        if (!is_object($callable) || !method_exists($callable, '__invoke')) {
            throw new \InvalidArgumentException('Extension service definition is not a Closure or invokable object.');
        }

        $factory = $this->values[$id];

        $extended = function ($c) use ($callable, $factory) {
            return $callable($factory($c), $c);
        };

        if (isset($this->factories[$factory])) {
            $this->factories->detach($factory);
            $this->factories->attach($extended);
        }

        return $this[$id] = $extended;
    }

    /**
     * Returns all defined value names.
     *
     * @return array An array of value names
     * 获取所有的 key
     */
    public function keys()
    {
        return array_keys($this->values);
    }

    /**
     * Registers a service provider.
     *
     * @param ServiceProviderInterface $provider A ServiceProviderInterface instance
     * @param array                    $values   An array of values that customizes the provider
     *
     * @return static
     * 注册自己的服务用的,后续文章体现
     */
    public function register(ServiceProviderInterface $provider, array $values = array())
    {
        $provider->register($this);

        foreach ($values as $key => $value) {
            $this[$key] = $value;
        }

        return $this;
    }
}

好吧,上面注释的都已经写出来了,个人觉得很简单,但是有几个方法我觉得可以扩展开来说,可能在过几天的文章里面展开来说说,基本上就是 register、extend和 raw 这几个方法的具体说明了。

哦对了,开始我觉得 factory 和 protect 方法差不多,其实还是有区别的,就是 factory 会有一个 $container 的参数,protect 方法就是存储的普通方法,区别就这么简单了。不过更多的方法,也会在后续文章说明的。


npm 以及 webpack 的一些笔记

先说点没用的,工作了3年了,相关东西也都接触一些,但是前端呢,还是按照以前的套路,做页面模版,写 js,写 css,但是现代相关的东西却没有深入的了解过。这不好啊,趁着现在有些空闲时间就想学习一下vue,但是 vue-cli 是使用 webpack 打包的,所以第一步就应该学习一下 webpack 趁机了解一下现代前端的开发思想。

本篇笔记总结自: http://www.jianshu.com/p/42e11515c10f,并针对笔记当日的最新版本对配置项进行响应的配置

安装 webpack

//全局安装
npm install -g webpack
//安装到你的项目目录
npm install --save-dev webpack

编译项目

webpack {entry file/入口文件} {destination for bundled file/存放bundle.js的地方}

不适用繁杂的命令,使用配置文件编译项目

module.exports = {
  entry:  __dirname + "/app/main.js",//已多次提及的唯一入口文件
  output: {
    path: __dirname + "/public",//打包后的文件存放的地方
    filename: "bundle.js"//打包后输出文件的文件名
  }
}

使用 node 的 package.json 设置 script 来执行编译

// 在package.json 的 scripts 里面添加下面的命令
"build": "webpack"
// 前面的是指在利用 npm run 后面执行的命令,问号后面的是真正执行的命令

使用webpack构建本地服务器

// 在 webpck.config.js 加入下面的配置文件
devServer: {
    contentBase: "./public",//本地服务器所加载的页面所在的目录
    // colors: true,//终端中输出结果为彩色 新版本貌似不需要这个了
    historyApiFallback: true,//不跳转
    inline: true//实时刷新
  } 

大概就这么多吧,Loader 和 Bable 没有总结,毕竟这两个扩展性比较强,需要用的时候,在查或者看文档就 ok 了,基本上 webpack 也就了解了一下了。

嘿呀,好久没有写东西了,很爽啊,正在逐步找回节奏,慢慢笔记会更好的。加油


又是一篇阶段性的总结2017年02月26日

从年后回来以后状态就一直不是很好,不过开心的事,在前两天状态终于有了提升,然后又通过这个周末的休息,肯定可以回到以前的状态了,过完年以后自己就一直有些焦虑,思考了很多问题,毕竟年龄都已经29了,还在跟一些95年的小朋友们在开发的一线打拼,有些压力,有些困惑,自己将来的职业路线应该如何。自己还不知道,昨天跟女朋友的弟弟一起吃了个饭,让我有了一些想法,也有些蒙圈,总之啊,蒙圈。

刚才跟女朋友又聊了聊,最后认定了一些东西,就是先努力的工作吧,否则说什么都是扯淡,先赚钱,先工作,更努力就好了。加油吧。开始学习了


最近的一些总结

转眼开工已经半个月,小妞还在努力的找工作做,加油吧,今天算是把黑苹果完善完毕了,剩下的小问题也可以忽略不计了,改天测试一下休眠也就完事了。明天无线网卡一到也就原生可以从app store下载东西了。

黑苹果昨晚也算是如释重负了一下,一些计划也该实施了,毕竟拖太久不好,计划其实也没啥,就是学习,只不过学习什么最近有些乱,很乱很乱,明天是周末需要捋顺一下,目前的计划有redis一本书,php一本书,vue或者react选择一个学习一下。

然后就是这样吧,又一篇流水账搞定了,哈哈。最后,输入法看样子还得是百度啊,搜狗不习惯