0%

每个人的心里都有一片属于自己的森林,迷失的人迷失了,相遇的人会再相遇
今天写一个demo,遇到一个问题,平时框架用多了,下意识的就以为use就能引入类,导致一直跑不成功,后来才意识到use与引用类并不是一回事。use只是指定了要使用哪个命名空间下的类,但是并不会引入类,类的引用还是需要使用include或require。

不使用命名空间

我们的所有的php文件都没有申明使用命名空间, 所有相关文件的引入使用include或require, 并需要指明文件的具体路径

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php

include_once 'AnimalInterface.php';
include_once 'Cat.php';
include_once 'Dog.php';

class Demo
{
public function action(AnimalInterface $animal)
{
return $animal->run();
}
}

$demo = new Demo();

echo $demo->action(new Cat());

echo $demo->action(new Dog());

注意:使用 include_once 可以防止文件重复引入定义

如果不使用命名空间, 那么我们的同一个文件夹就不能重复定义相同的类名, 如果需要解决这个重名的冲突, 就需要放在不同的文件夹下面, 或者申明不同的命名空间;

使用命名空间

申明使用命名空间

1
2
3
4
5
6
7
8
<?php

namespace App;

interface AnimalInterface
{
public function run();
}

申明以后所有需要引入这个文件都必须使用use

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php

use App\AnimalInterface;

include_once 'AnimalInterface.php';

class Dog implements AnimalInterface
{
public function run()
{
return 'dog run';
}
}

如果引用的文件是在同一个命名空间下, 则无需使用use

1
2
3
4
5
6
7
8
<?php

namespace App;

interface AnimalInterface
{
public function run();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php

namespace App;

include_once 'AnimalInterface.php';
include_once 'Cat.php';
include_once 'Dog.php';

class Demo
{
public function action(AnimalInterface $animal)
{
return $animal->run();
}
}

如果被引入的文件没有申明命名空间,则默认全局命名空间\

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php

namespace App\Index;
use App\AnimalInterface;

include_once 'AnimalInterface.php';
include_once 'Cat.php';
include_once 'Dog.php';

class Demo
{
public function action(AnimalInterface $animal)
{
return $animal->run();
}
}

$demo = new Demo();

echo $demo->action(new \Cat());

echo $demo->action(new \Dog());
1
2
3
4
5
6
7
8
9
10
11
12
13
<?php

use App\AnimalInterface;

include_once 'AnimalInterface.php';

class Dog implements AnimalInterface
{
public function run()
{
return 'dog run';
}
}

自动载入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php

namespace App\Index;
use App\AnimalInterface;

spl_autoload_register(function ($filename) {
if ($filename) {
if (file_exists($filename.'.php')) {
include_once $filename.'.php';
}
}
});

//include_once 'AnimalInterface.php';
//include_once 'Cat.php';
//include_once 'Dog.php';

class Demo
{
public function action(AnimalInterface $animal)
{
return $animal->run();
}
}

$demo = new Demo();

echo $demo->action(new \Cat());

echo $demo->action(new \Dog());

所有文件的自动载入需要在spl_autoload_register这个函数中通过include_once实现;

PSR

命名空间跟文件加载并无直接关系,只是有些语言,将命名空间结构和文件结构对应起来了。 以php为例,一般的命名空间结构,跟php文件结构是存在映射关系的,通过命名空间名称,就能算出该类的实际存储位置, 然后实例化的时候,会触发用设置的spl自动加载函数将文件引入。

后来我终于知道 , 它并不是我的花 ,我只是恰好途径了它的盛放。

说明

封装是类的构建过程,php具有;php也具有继承的特性。唯独这个多态,php体现的十分模糊。原因是php是弱类型语言。
java的多态体现的十分清晰,大体分两类:父类引用指向子类对象;接口引用指向实现接口的类对象。java声明变量时都要给变量设定类型,所以存在什么父类引用和接口引用。而php则没有这点体现,php声明变量不需要给变量设定类型,一个变量可以指向不同的数据类型。所以,php不具有像java一样的多态。

多态,作为面向对象编程中的一种设计模式,指的是通过遵循同一个interface,类可以有不同的功能实现(相当于说,有多种形态)。
在编程世界里,多态形式可以让我们的程序更加地模块化,易于扩展,而不是到处都是基于不同状态的条件判断,比如动不动就switch,动不动就层层嵌套if判断,这种情况下,十有八九是你的代码“有问题”了。

Interfaces

interface里可以定义方法名及相应参数,任何实现这个interface的类必须具体实现interface里定义的所有抽象方法,一个class可以实现多个interface

1
2
3
4
5
interface MyInterface {
public function doThis();
public function doThat();
public function setName($name);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 正确的做法
class MyClass implements MyInterface {
protected $name;
public function doThis() {
// code that does this
}
public function doThat() {
// code that does that
}
public function setName($name) {
$this->name = $name;
}
}

// 无效的做法
class MyClass implements MyInterface {
// 缺少 doThis()方法!

private function doThat() {
// 这个方法必须也是public!
}
public function setName() {
// 缺少 name 参数!
}
}

Abstract

Abstract Class可以说是介于interface和普通class之间,它既可以通过abstract method的形式定义统一的接口,又可以定义具体的功能实现。一个扩展了该Abstract Class的普通class,必须得具体实现该Abstract Class的所有抽象方法。

1
2
3
4
5
6
7
8
abstract class MyAbstract {
public $name;
public function doThis() {
// do this
}
abstract public function doThat();
abstract public function setName($name);
}

问题的引出

假设你有一个articleclass:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Article {
public $title;
public $author;
public $date;
public $category;

public function __construct($title, $author, $date, $category = 0) {
$this->title = $title;
$this->author = $author;
$this->date = $date;
$this->category = $category;
}
}

现在呢,你想添加一个方法,来以不同的形式输出article相关的信息,比如说XML格式,或者说JSON格式。
可能你一开始会想着这么来处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Article {
//...
public function write($type) {
$ret = '';
switch($type) {
case 'XML':
$ret = '<article>';
$ret .= '<title>' . $obj->title . '</title>';
$ret .= '<author>' . $obj->author . '</author>';
$ret .= '<date>' . $obj->date . '</date>';
$ret .= '<category>' . $obj->category . '</category>';
$ret .= '</article>';
break;
case 'JSON':
$array = array('article' => $obj);
$ret = json_encode($array);
break;
}
return $ret;
}
}

虽然功能上能实现效果,但是看上去很糟糕,不是吗?假设,将来你又想加上其他的格式,那该怎么办?再加几个case判断,这代码得多臃肿呢?

关于面向对象,有一个很重要的原则就是,一个class应该只做份内之事。每当你遇到大块的条件判断的时候,你就应该有所警醒,因为很可能这个时候你已经在同一个class或method下,硬要去做太多的事情了。那么这个时候,也就是该尝试多态实现了。

尝试解决

定义 Interface

1
2
3
interface Writer {
public function write(Article $obj);
}

具体实现 Interface

XMLWriter可以这样来实现:

1
2
3
4
5
6
7
8
9
10
11
class XMLWriter implements Writer {
public function write(Article $obj) {
$ret = '<article>';
$ret .= '<title>' . $obj->title . '</title>';
$ret .= '<author>' . $obj->author . '</author>';
$ret .= '<date>' . $obj->date . '</date>';
$ret .= '<category>' . $obj->category . '</category>';
$ret .= '</article>';
return $ret;
}
}

JSONWriter:

1
2
3
4
5
6
class JSONWriter implements Writer {
public function write(Article $obj) {
$array = array('article' => $obj);
return json_encode($array);
}
}

这样每一种个的class只负责各自的那一件事。

具体调用

1
2
3
4
5
6
class Article {
//...
public function write(Writer $writer) {
return $writer->write($this);
}
}

这样article的write方法接收的是一个实现了Writer这个interface的具体类,article不再需要关注具体该用什么样的格式,那已经不是它要负责的了,交给背后具体的Writer去处理就好了。

http://pilishen.com/posts/Understanding-and-Applying-Polymorphism-in-PHP

人与人拼到最后,拼的就是身体。身材好,就是一种实力。
这是个以貌取人的时代,没人有义务透过你臃肿的身材,去发现你优秀的内心。 你的身材,就是你的名片。 它能折射出你内在的品质、性格、习惯……千万别因身材让人看低了你的层次。

这是一个看身材的时代

去年曾有一条新闻:上海某著名小学招新生,面试家长,看家长身材,肥胖的不要。
这条新闻一出,顿时家长们炸了锅。有赞同此举的家长留言:
“我觉得非常好,肥胖的人自我管理能力差,还怪小孩不听话。”
“我觉得太赞了。自我管理能力低下的家长肯定无力配合超一流的教育啊。老外的私立学校也很严格,有钱都能进的你愿意往里挤吗?”
“我觉得看家长身材肥胖可以反映出一些问题的,首先肥胖不是短时间形成的,应该是长期不注意饮食和运动造成的。
家长连自己都没管好,你相信他们会管好孩子吗?自己都没有信心去坚持的东西,还会指望他们鼓励孩子去坚持?”
“教育孩子最好的方法是让自己变得优秀,给孩子做榜样。如果想让你的孩子成为你想象中的那个人,那么,你先成为那个人吧。”……
这个社会对胖子太残忍了—-找对象时被嫌弃,找工作时受歧视,好不容易找到对象结婚生子了吧,以为生活总算上了正轨,结果,没想到身材还能影响下一代的教育。
果然,这是个看身材的时代。
别以为你年长,就不用看身材了,没想到,作为家长,还要看身材。
如果你是胖子,孩子都要被你拖累。

身材好,也是一种实力

一个人的身材,25岁前,是爹妈给的;25岁之后,是自己修的。
能管好自己身材的人,往往能管理好自己的生活和工作。反之,臃肿的身材背后,可能是一团乱糟糟的生活。
我们公司副总裁,来自法国的欧总,就是个身材超好的高富帅,不过,是个50多岁的老帅哥。
他每天5:30起床,然后去操场跑步。有一段时间要参加“汉马”—-武汉马拉松赛,所以他更是加大了训练量。
欧总管理着公司最重要也是最忙碌的制造领域,每天提前半小时上班,还经常出差,别看他一把年纪了,可每天精力旺盛得像个小伙子。
的确,当领导要讲资历、论能力,但更要拼体力。经常的出差,坐飞机、坐火车,不规律的作息,没有良好的体质是吃不消的。
我的同事老张,就是因为胖,工作一直没有得到升迁。肥胖真的会影响一个人的职业生涯。
有一次,领导召开一个内容枯燥的会议。胖人精力不好,特别容易打瞌睡,老张听着听着竟然睡着了,脑袋还时不时“小鸡啄米”。
圆桌会议室里,他正好坐领导对面,领导重重地咳嗽了两声,老张从睡梦中惊醒,继续听讲。结果没一会儿,他又犯起困来,领导一一收在眼底。
肥胖,给工作带来影响,生活质量也大打折扣,还谈什么奋斗拼搏呢?
人与人拼到最后,拼的就是身体。身材好,就是一种实力。

你的身材,就是你的阶层

判断一个人的阶层,最简单的办法,就是看TA的身材。
正如保罗·福塞尔在《格调》一书中所说:
“你的体重就是你社会等级的宣言。一百年前,肥胖是成功的标志。但那样的日子已经一去不复返了。今天,肥胖是中下阶层的标志。与中上层阶级和中产阶级相比,中下阶层的肥胖者是前者的四倍。”
CCL领导力调研也表明:《财富》500强公司的首席执行官中找不到一个体重超标的人。
想想也是。那些受过良好教育、有强烈进取心、努力奋斗、事业有成的人,象普京、奥巴马、马云、李彦宏、俞敏洪……大多都是身材匀称、温文尔雅的人。
而那些家境贫困、庸庸碌碌、不思进取的人群,我们更容易看到大腹便便、体态臃肿、举止粗鲁的人。
英国纪录片《人生7年》也印证了这一事实。该片选择了14个不同阶层的孩子进行跟踪拍摄,每七年记录一次:从7岁开始、14岁、21岁……一直到56岁。
这是完全的真人秀,记录了普通英国人的人生。
片中的一对精英阶级夫妇 56岁时依然保持着好身材;由原中产阶级晋升为精英阶级的教授夫妻和公务员夫妻,体型也不错
而那些底层阶级长大的男人们,虽然有几个年轻时也英俊帅气,但最终他们几乎全都成了胖子或秃子,尤其是他们的妻子,身材变形得更厉害。
外国如此,中国也趋于这样。
索福瑞集团的调研显示,在中国,中低收入群体已占肥胖人口中的绝大多数比例。
为什么这个社会穷人越胖,富人越瘦?

瘦很昂贵,你胖,因为你穷

造成肥胖的原因,除遗传的影响外,主要就是不合理的饮食及运动量太少。
油炸食物、快餐等垃圾食品都让人容易变胖。而吃进去这么多热量,不运动,就会产生肥胖。
很多穷人没有生活,只有生存。
他们经常加班、熬夜、缺少睡眠、暴饮暴食或饮食不规律;生存的压力山大,哪有时间和精力去锻炼身体、控制饮食?
况且他们受教育程度普遍不高,也难有身材管理的意识和知识。所以,穷人的“过劳肥”越来越多。
而富人正相反。越来越多的富人意识到,拥有健康的身体是一笔无价的财富。
他们有时间有金钱对身体进行投资,他们愿意选择绿色、有机、低热量的食物,舍得在健身上花时间,也承担得起上健身房、请私人教练的大把银子。
国内曾有一项关于财富和运动关系的报告,数据显示:那些拥有财富更多的人倾向于更多的运动。大数据显示,每日行走8000步以上的人群平均收入高于8000步以下人群6.4%。
果然,好身材就像奢侈品,多属于富人阶层。
瘦很昂贵,穷人消费不起。你胖,是因为你穷。

你的身材里藏着自律

身材和时间金钱有关,没错,但关系更大的是,自律和意志力。
正如网上对《人生7年》的评价:
人人都只看到了精英阶层与生俱来优越的家庭条件和社会地位,羡慕他们有私家健身房,有私教,认为他们能有健康体魄、匀称的身材是理所当然的,可是又有谁看到他们在饮食控制、健身等方面的自律?
这种自律,远远强于底层阶级。
要知道那些有六块腹肌的男人和永远保持好身材的女人,他们拥有你想象不到的自律和意志力。
钟汉良曾晒过他的早餐,只有一片面包,几个蘑菇。
郭富城,坚持健身二十余年,每天最少跑步半小时。即使到外地,也会要求入住24小时开放健身房的酒店,要是酒店没有健身房的话,他会自备绳子在房间跳绳。
刘德华,为了拥有六块腹肌与紧实的胸肌线条,把家里变成了健身房。开演唱会前他会坚持长跑练气,拍戏时他会利用空挡举哑铃,每天再忙也要运动。
严歌苓,不仅在写作上自律,还会在繁忙的工作中,坚持锻炼身体,游泳和跑步。她在餐厅等朋友时,还不忘趴地上做平板支撑。
她说:“形象是女人的纪律”。
正是几十年如一日,钢铁般的意志自律着,所以她60多岁了,仍保持着纤细的身材和优雅的状态……
人人都知道“管住嘴,迈开腿”的道理,可又有几人能像他们这样做到呢?

转载自公众号:少女兔

在没有充分的知识作为前提的情况下, 即使行了万里路, 也不过是邮差而已。
There are a ton of helper methods in Laravel that make development more efficient. If you work with the framework, I encourage you to see what helpers you can introduce in your day-to-day work. In this blog post, I’d like to point out a few of my favorites.

data_get

The data_get() helper allows you to get a value from an array or object with dot notation. This functions similarly to array_get() as well. The optional third parameter can be used to supply a default value if the key is not found.

1
2
3
4
5
6
7
8
9
$array = ['albums' => ['rock' => ['count' => 75]]];

$count = data_get($array, 'albums.rock.count'); // 75
$avgCost = data_get($array, 'albums.rock.avg_cost', 0); // 0

$object->albums->rock->count = 75;

$count = data_get($object, 'albums.rock.count'); // 75
$avgCost = data_get($object, 'albums.rock.avg_cost', 0); // 0

If you use a “wildcard” (*) in your dot notation, Laravel will return an array of results.

1
2
$array = ['albums' => ['rock' => ['count' => 75], 'punk' => ['count' => 12]]];
$counts = data_get($array, 'albums.*.count'); // [75, 12]

str_plural

The str_plural() helper converts a string to its plural form. Currently, only English is supported. The optional second parameter will allow the helper to choose the plural or singular form. The helper is also smart enough to help with “uncountable” or special case words.

1
2
3
4
5
6
7
8
9
10
tr_plural('dog'); // dogs
str_plural('cat'); // cats

str_plural('dog', 2); // dogs
str_plural('cat', 1); // cat

str_plural('child'); // children
str_plural('person'); // people
str_plural('fish'); // fish
str_plural('deer', 2); // deer

route

The route() helper generates a URL for the specified named route. The optional second argument will accept additional route parameters. If additional parameters aren’t named Laravel will try it’s best to match them to the attributes on the route then will add any remaining parameters to the end of the URL.

1
2
3
4
5
6
7
8
9
10
11
12
Route::get('burgers', 'BurgersController@index')->name('burgers');
route('burgers'); // http://example.com/burgers
route('burgers', ['order_by' => 'price']); // http://example.com/burgers?order_by=price

Route::get('burgers/{id}', 'BurgersController@show')->name('burgers.show');
route('burgers.show', 1); // http://example.com/burgers/1
route('burgers.show', ['id' => 1]); // http://example.com/burgers/1

Route::get('employees/{id}/{name}', 'EmployeesController@show')->name('employees.show');
route('employees.show', [5, 'chris']); // http://example.com/employees/5/chris
route('employees.show', ['id' => 5, 'name' => 'chris']); // http://example.com/employees/5/chris
route('employees.show', ['id' => 5, 'name' => 'chris', 'hide' => 'email']); // http://example.com/employees/5/chris?hide=email

abort_if

The abort_if() helper throws an exception if the given expression evaluates to true. The optional third parameter will accept a custom response text, and the optional fourth argument will accept an array of headers.

1
2
3
abort_if(! Auth::user()->isAdmin(), 403);
abort_if(! Auth::user()->isAdmin(), 403, 'Sorry, you are not an admin');
abort_if(Auth::user()->isCustomer(), 403);

So many of us have done something similar to the below example, and the abort_if() helper can cut it down to one line.

1
2
3
4
5
6
7
8
9
10
11
12
13
// In "admin" specific controller
public function index()
{
if (! Auth::user()->isAdmin()) {
abort(403, 'Sorry, you are not an admin');
}
}

// better!
public function index()
{
abort_if(! Auth::user()->isAdmin(), 403);
}

optional

The optional() helper allows you to access properties or call methods on an object. If the given object is null, properties and methods will return null instead of causing an error.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// User 1 exists, with account
$user1 = User::find(1);
$accountId = $user1->account->id; // 123

// User 2 exists, without account
$user2 = User::find(2);
$accountId = $user2->account->id; // PHP Error: Trying to get property of non-object

// Fix without optional()
$accountId = $user2->account ? $user2->account->id : null; // null
$accountId = $user2->account->id ?? null; // null

// Fix with optional()
$accountId = optional($user2->account)->id; // null

The optional() helper is ideal when using objects you might not own or calling nested data within Eloquent relationships that may, or may not, be available.

https://laravel-news.com/5-laravel-helpers-make-life-easier

别说东南西北,请说左右好么

问题

项目开发环境报了错,报错信息如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
npm ERR! code ELIFECYCLE
npm ERR! errno 2
npm ERR! @ development: `cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js`
npm ERR! Exit status 2
npm ERR!
npm ERR! Failed at the @ development script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR! C:\Users\Administrator\AppData\Roaming\npm-cache\_logs\2018-02-23T02_05_24_275Z-debug.log
npm ERR! code ELIFECYCLE
npm ERR! errno 2
npm ERR! @ dev: `npm run development`
npm ERR! Exit status 2
npm ERR!
npm ERR! Failed at the @ dev script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR! C:\Users\Administrator\AppData\Roaming\npm-cache\_logs\2018-02-23T02_05_24_301Z-debug.log

解法一

node_modules 目录删除
执行命令

1
2
npm cache clear --force  
npm install -g npm

解法二

查看 node_modules 目录的权限是否存在问题

解法三

检查是否有异常端口占用

努力, 奋斗
新年第一天, 带病上班, 感冒加口腔溃疡, 难受的很.想起前天晚上看到的那篇文章, 就想发发感慨, 长大了好多事儿就觉得自己无能为力, 除了写代码, 也没有其他赚钱维生的技能, 在家里的这几天,翻看以前的旧照片, 能看到父母一点一点的变老,我们几个孩子都已经长大, 相继结婚生子, 可父母仍旧每天不辞辛劳的在外奔波, 想为他们做点儿啥, 却发现自己真的是... 没钱, 工作忙, 不敢请假, 房租, 房贷, 各种花销都让我望而却步, 一次次打消带父母出去玩的念头, 或者是让父母停下来, 找点儿轻松一点儿活儿来做, 但是, 哎....

如果亲人健在的时候,有什么都给他们吧。

分享柳岩的一个故事, 她说:我爸上个月身体状况不太好,然后是在医院度过70岁生日,但是我很高兴自豪的是,我有足够的经济能力,给他最好的医疗条件。她说:总是有人说要送什么祝福,最大的祝福,就是希望父母健健康康的,因为这样才能给我们机会,实现我们小时候的诺言,我要给你们买大房子,我要带你们周游世界。

时间不会等你,父母衰老的速度不会等你。

一个人真正的成熟是什么?就是时间推着你往前走,你发现自己忽然在迎来客往里,变成了越来越重要的那一个人。而你,也慢慢接受着这一切,并约定俗成。中年人,是没有资格说“不”的,哪怕你私心觉得这是你的权利。上有老,下有小,是每个中年人不得不面临的。中年危机不是某个时代的焦虑,而是属于每个人的焦虑。中年人的焦虑,与生俱来,而你消失的那一刻,你已经进入了老年,那是人生的另一个阶段。中年,是一种责任,你再瘦弱也要扛起来,什么疲于奔命,如果能通过你疲于奔命,改变家族的命运,请认真努力。

越长大越明白,什么都可以等,但爱亲人这件事,真的等不了。

李健写自己的父亲生病的时候,当时我泪如雨下。“我把当时仅有的几万块钱全拿出来了,我意识到,有些时候钱是多么重要。随后他的病情每况愈下,生命的最后阶段,我送他回哈尔滨。火车上,他已经很虚弱了,每次去洗手间都要我搀扶或者背着他,我一宿没怎么睡觉。记得当我背着他时,他说了句,原谅爸爸。那一瞬间,我强忍住了泪水。他太客气了,竟然对自己从小背到大的儿子客气,而我只是背了他几次而已。”你看,亲情有时真的是一瞬间的。你说你长大后,我就可以给你住大房子。你说你长大后,我就可以带你吃所有你喜欢的。你说你放心,你想去哪儿都可以,我有能力。请!现在!就做!一刻不停。

加油,好好待父母,也好好待父母爱的自己

子欲养而亲不待。我从前是不太敏感这样的话,觉得父母健在,并未到达需要我们告别前匆匆完成的时刻。而这些年,看到一个个越来越熟悉的人经历着离别,好像一切又离自己慢慢近了。对于我们这些中年人来说,尤其是最大的骄傲,莫过于:爸妈,你们想吃什么尽管买吧,我有钱;爸妈,我有大房子,你有空来住吧;爸妈,你们别担心,万一生病了,我有足够的钱给你们治病。因为是你们的儿女,因为你们是我们的亲人。今生一见,来世不知道是否还能遇见,所以,珍惜以及相爱,毕竟匆匆而过。

今天完了就要回家过年了...

同时验证两个字段唯一

控制器

1
$this->validate($request, SiteMail::rules());

模型

1
2
3
4
5
6
7
8
9
10
public static function rules($request = null)
{
return [
'site_id' => 'required|integer',
'subject' => 'required|max:256',
'type' => Rule::unique('site_mails')->where(function ($query) {
$query->where('site_id', request('site_id'));
}),
];
}

在抱怨自己赚钱之少之前先努力学着让自己值钱。
十多年来,我们一直使用 XMLHttpRequest(XHR)来发送异步请求,XHR 很实用,但并不是一个设计优良的 API,在设计上并不符合职责分离原则,输入、输出以及状态都杂糅在同一对象中,并用事件机制来跟踪状态变化。并且,基于事件的模型与最近流行的 Promise 和 generator 异步编程模型不太友好。

Fetch API 旨在修正上述缺陷,它提供了与 HTTP 语义相同的 JS 语法,简单来说,它引入了 fetch() 这个实用的方法来获取网络资源。

在 Fetch 规范中对 API 进行了定义,它结合 ServiceWorkers,尝试做到如下优化:

  • 改善离线体验
  • 保持可扩展性

简单示例

Fetch API 中最常用的是 fetch() 方法,该方法最简单的形式是,接受一个 URL 参数并返回以一个 promise 对象:

1
2
3
4
5
6
7
8
9
10
11
12
fetch("/data.json").then(function(res) {
// res instanceof Response == true.
if (res.ok) {
res.json().then(function(data) {
console.log(data.entries);
});
} else {
console.log("Looks like the response wasn't perfect, got status", res.status);
}
}, function(e) {
console.log("Fetch failed!", e);
});

如果是提交一个POST请求,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
fetch("http://www.example.org/submit.php", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body: "firstName=Nikhil&favColor=blue&password=easytoguess"
}).then(function(res) {
if (res.ok) {
alert("Perfect! Your settings are saved.");
} else if (res.status == 401) {
alert("Oops! You are not authorized.");
}
}, function(e) {
alert("Error submitting form!");
});

fetch() 方法的参数和 Request() 构造函数的参数完全一致,所以你可以传任意复杂的参数来实现更强大的 fetch(),下面将详细介绍。

Headers

Fetch 引入了 3 个接口,分别是 Headers,Request 和 Response。他们直接对应于的 HTTP 中相应的概念,但是基于隐私和安全考虑,也有些区别,例如支持 CORS 规则以及保证 cookies 不能被第三方获取。

Headers 接口是一个简单的键值对:

1
2
3
4
5
6
ar content = "Hello World";
var reqHeaders = new Headers();
reqHeaders.append("Content-Type", "text/plain"
reqHeaders.append("Content-Length", content.length.toString());
reqHeaders.append("X-Custom-Header", "ProcessThisImmediately");

也可以给构造函数传一个多维数组或 JS 字面量对象:

1
2
3
4
5
reqHeaders = new Headers({
"Content-Type": "text/plain",
"Content-Length": content.length.toString(),
"X-Custom-Header": "ProcessThisImmediately",
});

Headers 的内容可被检索:

1
2
3
4
5
6
7
8
9
10
console.log(reqHeaders.has("Content-Type")); // true
console.log(reqHeaders.has("Set-Cookie")); // false
reqHeaders.set("Content-Type", "text/html");
reqHeaders.append("X-Custom-Header", "AnotherValue");

console.log(reqHeaders.get("Content-Length")); // 11
console.log(reqHeaders.getAll("X-Custom-Header")); // ["ProcessThisImmediately", "AnotherValue"]

reqHeaders.delete("X-Custom-Header");
console.log(reqHeaders.getAll("X-Custom-Header")); // []

一些操作只在 ServiceWorkers 中可用,但这些 API 使得操作 header 更为方便。

由于 header 可以在发送请求时被发送或在收到响应时被接收,并规定了那些参数可写,所以在 Headers 对象中有个一 guard 属性,来指定哪些参数可以被改变。

可能的值如下:

  • “none”:默认值
  • “request”:Request.headers 对象只读
  • “request-no-cors”:在 no-cors 模式下,Request.headers 对象只读
  • “response”:Response.headers 对象只读
  • “immutable”:通常在 ServiceWorkers 中使用,所有 Header 对象都为只读
    在规范中对每个 guard 属性值有更详细的描述。例如,当 guard 为 request 时,你将不能添加或修改header 的 Content-Length 属性。

如果使用了一个不合法的 HTTP Header 名,那么 Headers 的方法通常都抛出 TypeError 异常。如果不小心写入了一个只读属性,也会抛出一个 TypeError 异常。除此以外,失败了将不抛出任何异常。例如:

1
2
3
4
5
6
var res = Response.error();
try {
res.headers.set("Origin", "http://mybank.com");
} catch(e) {
console.log("Cannot pretend to be a bank!");
}

Request

通过构造一个 Request 对象来获取网络资源,构造函数需要 URL、method 和 headers 参数,同时也可以提供请求体(body)、请求模式(mode)、credentials 和 cache hints 等参数。

最简单的形式如下:

1
2
3
var req = new Request("/index.html");
console.log(req.method); // "GET"
console.log(req.url); // "http://example.com/index.html"

也可以将一个 Request 对象传给构造函数,这将返回该对象的一个副本(这与 clone() 方法不同,后面将介绍)。

1
2
3
var copy = new Request(req);
console.log(copy.method); // "GET"
console.log(copy.url); // "http://example.com/index.html"

同时,这种形式通常只在 ServiceWorkers 中使用。

除 URL 之外的参数只能通过第二个参数传递,该参数是一个键值对:

1
2
3
4
5
6
7
var uploadReq = new Request("/uploadImage", {
method: "POST",
headers: {
"Content-Type": "image/png",
},
body: "image data"
});

mode 参数用来决定是否允许跨域请求,以及哪些 response 属性可读。可选的 mode 值为 “same-origin”、”no-cors”(默认)以及 “cors”。

same-origin

该模式很简单,如果一个请求是跨域的,那么将返回一个 error,这样确保所有的请求遵守同源策略。

1
2
3
4
5
6
var arbitraryUrl = document.getElementById("url-input").value;
fetch(arbitraryUrl, { mode: "same-origin" }).then(function(res) {
console.log("Response succeeded?", res.ok);
}, function(e) {
console.log("Please enter a same-origin URL!");
});

Response

Response 对象通常在 fetch() 的回调中获得,也可以通过 JS 构造,不过这通常只在 ServiceWorkers 中使用。

Response 对象中最常见的属性是 status(整数,默认值是 200)和statusText(默认值是 “OK”)。还有一个 ok 属性,这是 status 值为 200~299 时的语法糖。

另外,还有一个 type 属性,它的值可能是 “basic”、”cors”、”default”、”error” 或 “opaque”。

  • “basic”:同域的响应,除 Set-Cookie 和 Set-Cookie2 之外的所有 Header 可用
  • “cors”:Response 从一个合法的跨域请求获得,某些 Header 和 body 可读
  • “error”:网络错误。Response 对象的 status 属性为 0,headers 属性为空并且不可写。当 Response 对象从 Response.error() 中得到时,就是这种类型
  • “opaque”:在 “no-cors” 模式下请求了跨域资源。依靠服务端来做限制
    当 type 属性值为 “error” 时会导致 fetch() 方法的 Promise 被 reject,reject 回调的参数为 TypeError 对象。

还有一些属性只在 ServerWorker 下有效。在 ServerWorker 下返回一个 Response 的正确方式为:

1
2
3
4
5
addEventListener('fetch', function(event) {
event.respondWith(new Response("Response body", {
headers: { "Content-Type" : "text/plain" }
});
});

如你所见,Response 构造函数接收两个参数:返回的 body 和一个键值对对象,通过该对象来设置 status、statusText 和 headers 属性。

静态方法 Response.error() 将返回一个错误响应,Response.redirect(url, status) 将返回一个跳转响应。

http://bubkoo.com/2015/05/08/introduction-to-fetch/
https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch

既然庸庸碌碌也难逃一死,何不奋起一搏?

准备工作

  • docker安装

    1
    sudo yum install docker-ce
  • 主机安装并配置java环境, 要求使用解压版的jdk
    配置环境变量, 修改/etc/profile 加入以下内容,修改后 马上生效还需要运行 source /etc/profile

    1
    2
    3
    export JAVA_HOME=/usr/local/jdk1.8.0_161
    export PATH=$JAVA_HOME/bin:$PATH
    export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
  • 安装centos镜像

    1
    docker pull centos

安装过程

创建的一个空的文件夹build_jdk, 并将我们的jdk目录拷贝到这个目录:

1
cp -r jdk1.8.0_161 /root/build_jdk/

创建Dockerfile文件
需要将主机的jdk文件拷贝到镜像里, 并配置环境变量

1
2
3
4
5
6
FROM centos:latest
COPY jdk1.8.0_161 /usr/local/jdk1.8.0_161
ENV JAVA_HOME=/usr/local/jdk1.8.0_161
ENV PATH $JAVA_HOME/bin:$PATH
ENV CLASSPATH .:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
CMD /usr/sbin/init

生成镜像
在Dockerfile文件的文件加下执行

1
docker build -t centos:jdk .

注意后面的.代表当前目录
生成容器

1
docker run --privileged -d -p 8080:80 --name myjdk -v /home/demo:/var/www/html centos:jdk

–privileged 参数,给容器加特权,否则交互式方式进入容器无法操作一些譬如修改内核、修改系统参数、甚至启动服务等
-d 在后台启动
-p 端口映射
-v 文件夹共享
–name 给容器起一个名称
镜像名:镜像标签
启动容器的时候执行的命令, 必须要执行/usr/sbin/init这个命令,

nothing is impossible

问题

在 JavaScript 中 (a ==1 && a== 2 && a==3) 可能为 true 吗?

解答一

1
2
3
4
5
6
7
8
9
10
const a = {
i: 1,
toString: function () {
return a.i++;
}
}

if(a == 1 && a == 2 && a == 3) {
console.log('Hello World!');
}

当使用 == 时,如果两个参数的类型不一样,那么 JS 会尝试将其中一个的类型转换为和另一个相同。在这里左边对象,右边数字的情况下,会首先尝试调用 valueOf(如果可以调用的话)来将对象转换为数字,如果失败,再调用 toString。

解答二

1
2
3
4
5
6
var aᅠ = 1;
var a = 2;
var ᅠa = 3;
if(aᅠ==1 && a== 2 &&ᅠa==3) {
console.log("Why hello there!")
}

解答三

1
2
3
4
5
6
7
8
9
10
var i = 0;

with({
get a() {
return ++i;
}
}) {
if (a == 1 && a == 2 && a == 3)
console.log("wohoo");
}

解答四

1
2
3
a = [1,2,3];
a.join = a.shift;
console.log(a == 1 && a == 2 && a == 3);

https://stackoverflow.com/questions/48270127/can-a-1-a-2-a-3-ever-evaluate-to-true