phpspec入门

入门

  1. 执行bin/phpspec desc Markdown生成MarkdownSpec类
  2. 执行bin/phpspec run提示生成Markdown类
  3. 在MarkdownSpec类添加方法
    function it_converts_plain_text_to_html_paragraphs()
    {
        $this->toHtml("Hi, there")->shouldReturn("
<p>
    Hi, there
</p>
");
    }
  1. 执行bin/phpspec run提示生成Markdown类的toHtml方法
  2. 编写Markdown类的toHtml方法
    public function toHtml($argument1)
    {
        return "
<p>
    Hi, there11
</p>
";//这里故意写错
    }
  1. 执行bin/phpspec run
Markdown                                                                        
  11  - it converts plain text to html paragraphs
      expected "
<p>
    Hi, there
</p>
", but got "
<p>
    Hi, there11
</p>
".

                                      100%                                       1
1 specs
1 example (1 failed)
192ms

phpspec安装

安装

phpspec是一个php 5.6库,您将在项目开发环境中拥有它。在开始之前,请确保已经安装了PHP 5.6或7。

安装步骤

您可以通过Composer来安装phpspec。如果你还没有安装,请按照作Composer网站上的说明

安装方法1

执行命令composer require --dev phpspec/phpspec安装

安装方法2

1. 编辑composer.jsonrequire-dev节点添加”phpspec/phpspec”: “~3.0”
2. 执行composer update 或者composer install安装

composer内容
{
  “require-dev”: {
    “phpspec/phpspec”: “~3.0”
  },
  “config”: {
    “bin-dir”: “bin”
  },
  “autoload”: {
    “psr-0”: {
      “”: “src/”
    }
  }
}

Lumen5.X使用频率限制组件笔记

编写中间件,是根据vendor/illuminate/routing/Middleware/ThrottleRequests.php改写

备注:需要先配置cache

<?php

namespace App\Http\Middleware;

use Closure;
use Carbon\Carbon;
use Illuminate\Cache\RateLimiter;
use Symfony\Component\HttpFoundation\Response;

class ThrottleMiddleware
{
    /**
     * The rate limiter instance.
     *
     * @var \Illuminate\Cache\RateLimiter
     */
    protected $limiter;

    /**
     * Create a new request throttler.
     *
     * @param  \Illuminate\Cache\RateLimiter  $limiter
     * @return void
     */
    public function __construct(RateLimiter $limiter)
    {
        $this->limiter = $limiter;
    }

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @param  int  $maxAttempts
     * @param  float|int  $decayMinutes
     * @return mixed
     */
    public function handle($request, Closure $next, $maxAttempts = 60, $decayMinutes = 1)
    {
        $key = $this->resolveRequestSignature($request);

        if ($this->limiter->tooManyAttempts($key, $maxAttempts, $decayMinutes)) {
            return $this->buildResponse($key, $maxAttempts);
        }

        $this->limiter->hit($key, $decayMinutes);

        $response = $next($request);

        return $this->addHeaders(
            $response, $maxAttempts,
            $this->calculateRemainingAttempts($key, $maxAttempts)
        );
    }
    
    /**
     * Resolve request signature.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return string
     */
    protected function resolveRequestSignature($request)
    {
        return sha1(
            $request->method() .
            '|' . $request->server('SERVER_NAME') .
            '|' . $request->path() .
            '|' . $request->ip()
        );
    }
//    protected function resolveRequestSignature($request)
//    {
//        return $request->fingerprint();
//    }

    /**
     * Create a 'too many attempts' response.
     *
     * @param  string  $key
     * @param  int  $maxAttempts
     * @return \Symfony\Component\HttpFoundation\Response
     */
    protected function buildResponse($key, $maxAttempts)
    {
        $response = new Response('请求超出设定频率', 429);
        $retryAfter = $this->limiter->availableIn($key);

        return $this->addHeaders(
            $response, $maxAttempts,
            $this->calculateRemainingAttempts($key, $maxAttempts, $retryAfter),
            $retryAfter
        );
    }

    /**
     * Add the limit header information to the given response.
     *
     * @param  \Symfony\Component\HttpFoundation\Response  $response
     * @param  int  $maxAttempts
     * @param  int  $remainingAttempts
     * @param  int|null  $retryAfter
     * @return \Symfony\Component\HttpFoundation\Response
     */
    protected function addHeaders(Response $response, $maxAttempts, $remainingAttempts, $retryAfter = null)
    {
        $headers = [
            'X-RateLimit-Limit' => $maxAttempts,
            'X-RateLimit-Remaining' => $remainingAttempts,
        ];

        if (! is_null($retryAfter)) {
            $headers['Retry-After'] = $retryAfter;
            $headers['X-RateLimit-Reset'] = Carbon::now()->getTimestamp() + $retryAfter;
        }

        $response->headers->add($headers);

        return $response;
    }

    /**
     * Calculate the number of remaining attempts.
     *
     * @param  string  $key
     * @param  int  $maxAttempts
     * @param  int|null  $retryAfter
     * @return int
     */
    protected function calculateRemainingAttempts($key, $maxAttempts, $retryAfter = null)
    {
        if (is_null($retryAfter)) {
            return $this->limiter->retriesLeft($key, $maxAttempts);
        }

        return 0;
    }
}
//使用笔记
'middleware' => 'throttle:2,0.5'

php中的generator和yield

1.Generator
在编程这个领域,我们可以把它想象成一个可以生成一系列数据的工具,这个工具可以具体为一个类、一个函数或者是一个语句
定义:
http://de2.php.net/manual/en/class.generator.php
特点:
不能直接实例化使用new Generator()调用,必须使用yield

2.yield
在php中,yield关键字只能在函数中使用,代码执行到yield语句,函数的执行就会终止并返回yield表达式给Generator

当对Generator对象进行遍历迭代,那么带有yield语句的函数后的代码会执行
例子:
function a() {
    $b =23;
    yield $b;
    echo 1;
}
$c = a();
echo $c->current();//会输出23但是不会输出1
//遍历则会输出0=>23 1
foreach ($c as $k => $v) {
    echo $k . "=>". $v . PHP_EOL;
}

多条语句
function a() {
    yield 1;
    yield 2;
    yield 3;
}
$c = a();
//输出0=>1 1=>2 2=>3
foreach ($c as $k => $v) {
    echo $k . "=>". $v . PHP_EOL;
}
特性:每次迭代都只会执行前一次yield语句之后的代码,那Generator可以用于实现协程的原因。

3.用途
可以用来做协程
可以用来大量数据的集合(节约空间)

composer使用笔记

1.基本用法
require  monolog/monolog  1.0.*

2.包版本
确定版本	1.0.1
范围		>=1.0
范围AND		>=1.0,<2.0
范围OR		>2.0|<1.2
通配符		1.*
运算		~1.2等同于>=1.2,<2.0	大于1.2并且小于2.0版本

备注:~1.2.1是等同于>=1.2.1,<1.3

3.将composer.lock好composer.json提交到仓库当中方便协同工作

更多参考:https://getcomposer.org/doc/04-schema.md

负载均衡知识汇总

一、DNS轮询
1.实现
DNS配置多个IP域名解析(A记录)

2.优点
部署简单

3.缺点
非高可用(健康监测需人工干预)
会话状态需要共享(session共享)
扩容非实时(DNS解析缓存和TTL)
暴漏较多的外网IP

备注:DNS轮询是从域名层面做负载均衡

Continue reading

GO获取表单元素

1.如果使用Form[“username”]获取表单元素需调用ParseForm(),获取到的是数组
2.如果使用FormValue会自动调用ParseForm(),所以可以直接使用FormValue(“username”),获取到的是元素。等同于Form.Get

3.PostForm是获取POST表单当中的元素获取到的是数组,同样需要调用ParseForm(),PostFormValue获取的是元素

参考:https://github.com/astaxie/build-web-application-with-golang/blob/master/zh/04.1.md

Go操作MySQL示例【转】

package main

import (
	_ "github.com/go-sql-driver/mysql"
	"database/sql"
	"fmt"
)

func main() {
	db, err := sql.Open("mysql", "test:test@/test_demo?charset=utf8")
	//检查数据库链接
	checkErr(err)
	//插入数据
	stmt, err := db.Prepare("INSERT userinfo SET username=?,departname=?,created=?")
	checkErr(err)
	res, err := stmt.Exec("test", "研发部门", "2012-12-09")
	checkErr(err)
	//获取插入的ID
	id, err := res.LastInsertId()
	checkErr(err)
	fmt.Println(id)
	//更新数据
	stmt, err = db.Prepare("update userinfo set username=? where uid=?")
	checkErr(err)
	res, err = stmt.Exec("test1", id)
	checkErr(err)
	//获取更新的影响行数
	affect, err := res.RowsAffected()
	checkErr(err)
	fmt.Println(affect)
	//查询数据
	rows, err := db.Query("SELECT * FROM userinfo")
	checkErr(err)
	for rows.Next() {
		var uid int
		var username string
		var department string
		var created string
		err = rows.Scan(&uid, &username, &department, &created)
		checkErr(err)
		fmt.Println(uid)
		fmt.Println(username)
		fmt.Println(department)
		fmt.Println(created)
	}
	//删除数据
	stmt, err = db.Prepare("delete from userinfo where uid=?")
	checkErr(err)
	res, err = stmt.Exec(id)
	checkErr(err)
	affect, err = res.RowsAffected()
	checkErr(err)
	fmt.Println(affect)

	db.Close()

}

func checkErr(err error) {
	if err != nil {
		panic(err)
	}
}
GO连接数据库的一些格式
user@unix(/path/to/socket)/dbname?charset=utf8
user:password@tcp(localhost:5555)/dbname?charset=utf8
user:password@/dbname
user:password@tcp([de:ad:be:ef::ca:fe]:80)/dbname

Go命令介绍

1.go build	用于编译代码
2.go clean	用来移除当前源码包和关联源码包里面编译生成的文件
_obj/            旧的object目录,由Makefiles遗留
_test/           旧的test目录,由Makefiles遗留
_testmain.go     旧的gotest文件,由Makefiles遗留
test.out         旧的test记录,由Makefiles遗留
build.out        旧的test记录,由Makefiles遗留
*.[568ao]        object文件,由Makefiles遗留

DIR(.exe)        由go build产生
DIR.test(.exe)   由go test -c产生
MAINFILE(.exe)   由go build MAINFILE.go产生
*.so             由 SWIG 产生
3.go fmt 	格式化代码
4.go get	获取远程包
5.go install 生成结果文件并移动到pkg和bin目录下
6.go test	自动读取源码目录*_test.go文件,生成并运行测试用的可执行文件
7.go tool	命令集
8.go generate	便以前自动化生成某类嗲吗
9.godoc		文档工具
10.go version 查看go版本
11.go env 查看当前go的环境变量
12.go run 编译并运行go程序
Tagged