[关闭]
@42withyou 2016-09-23T07:25:18.000000Z 字数 8221 阅读 596

容器,依赖注入,控制反转

未分类


  1. public function __construct()
  2. {
  3. $this->users = new UserRepository;
  4. }
  5. public function __construct(UserRepository $users)
  6. {
  7. $this->users = $users;
  8. }

注册一个实例到容器中

  1. $this->app['context'] = $this->app->share(function ($app) {
  2. return new Context;
  3. });

或者绑定一个 Interface 到一个实体(Entity)

  1. $this->app->bind(
  2. \App\Repositories\Api\UserRepositoryInterface::class,
  3. \App\Repositories\Api\Eloquent\UserRepository::class
  4. );

参考 灵析 api

不过类似 context 这种需求,在整个应用生命周期只需要一个,所以

  1. $this->app->singleton('context', function () {
  2. return $this->app->make(\App\Utilities\Context\Context::class);
  3. });

关于 Conainer 的实现, 有 laravel 的实现方式 Illuminate\Container,基本上出了 Thinkphp 所有国外框架都有容器这么一个概念。

参考 Demo

Facade

  1. <?php
  2. use Context;
  3. class HomeController
  4. {
  5. public function index()
  6. {
  7. Context::all();
  8. }
  9. }
  1. <?php
  2. class ContextFacade extends Facade
  3. {
  4. protected static function getFacadeAccessor()
  5. {
  6. return 'context';
  7. }
  8. }
  1. <?php
  2. abstract class Facade
  3. {
  4. protected static function getFacadeAccessor()
  5. {
  6. throw new RuntimeException('Facade does not implement getFacadeAccessor method.');
  7. }
  8. public static function __callStatic($method, $args)
  9. {
  10. // 返回容器中绑定的对象
  11. $instance = static::getFacadeRoot();
  12. if (! $instance) {
  13. throw new RuntimeException('A facade root has not been set.');
  14. }
  15. // ...$args ???
  16. return $instance->$method(...$args);
  17. }
  18. }

关于解构符(spread operator)

  1. function foo($a, ...$args)
  2. {
  3. $a // 1,
  4. $args // [2,3,4]
  5. }
  6. foo(...[1,2,3,4]);

Collection

先看个例子感受一波

  1. return collect($users)
  2. ->filter(function ($user) {
  3. return $user->isActive();
  4. })
  5. // ->reject(function ($user) { return $user->notActive() })
  6. ->map(function ($user) {
  7. return $user->posts;
  8. })
  9. ->reduce(function ($total, $item) {
  10. return $total + $item->commentCount;
  11. }, 0);
  12. // ->sum('commentCount');
  1. $people = collect([
  2. ['name' => 'RryLee', 'single' => true, 'email' => 'RryLee@justering.com'],
  3. ['name' => 'Yekz', 'single' => true, 'email' => 'Yekz@justering.com'],
  4. ['name' => 'Ferman', 'single' => false, 'email' => 'Ferman@justering.com'],
  5. ['name' => 'Sky', 'single' => true, 'email' => 'Sky@justering.com'],
  6. ['name' => 'Casper', 'single' => false, 'email' => 'Casper@justering.com'],
  7. ]);
  8. $emails = [];
  9. foreach ($people as $person) {
  10. if ($person['single']) {
  11. $emails[] = $person['email'];
  12. }
  13. }
  14. // collection.
  15. $people->filter(function ($person) {
  16. return $person->single;
  17. })->pluck('email');
  1. $people = collect([
  2. [
  3. 'name' => 'RryLee',
  4. 'email' => 'RryLee@justering.com',
  5. 'projects' => [
  6. ['name' => 'api', 'code_line' => 7444],
  7. ['name' => 'cfnew', 'code_line' => 5020],
  8. ['name' => 'lingxi', 'code_line' => 1200],
  9. ],
  10. ],
  11. [
  12. 'name' => 'Yekz',
  13. 'email' => 'Yekz@justering.com',
  14. 'projects' => [
  15. ['name' => 'api', 'code_line' => 120],
  16. ['name' => 'cfnew', 'code_line' => 4000],
  17. ['name' => 'lingxi', 'code_line' => 8000],
  18. ['name' => 'mail', 'code_line' => 2122],
  19. ['name' => 'pay', 'code_line' => 1201],
  20. ],
  21. ],
  22. [
  23. 'name' => 'Ferman',
  24. 'email' => 'Ferman@justering.com',
  25. 'projects' => [
  26. ['name' => 'cfnew', 'code_line' => 3000],
  27. ['name' => 'lingxi', 'code_line' => 5000],
  28. ['name' => 'pay', 'code_line' => 7000],
  29. ],
  30. ],
  31. ]);
  32. $people->pluck('projects')
  33. /**
  34. * [
  35. * [
  36. ['name' => 'api', 'code_line' => 7444],
  37. ['name' => 'cfnew', 'code_line' => 5020],
  38. ['name' => 'lingxi', 'code_line' => 1200],
  39. * ],
  40. * [...],
  41. * [...],
  42. * ]
  43. */
  44. ->flatten(1)
  45. /**
  46. * [
  47. * ['name' => 'api', 'code_line' => 7444],
  48. * ['name' => ...],
  49. * ['name' => ...],
  50. * ]
  51. */
  52. ->groupBy('name')
  53. /**
  54. * [
  55. * 'api' => [
  56. * ['name' => 'api', 'code_line' => 7444],
  57. * ['name' => 'api', 'code_line' => ...],
  58. * ['name' => 'api', 'code_line' => ...],
  59. * ],
  60. * 'cfnew' => [
  61. * ...
  62. * ]
  63. * ]
  64. */
  65. ->map(function ($groupedProjects) {
  66. return $groupedProjects->sum('code_line');
  67. })
  68. ->sort()
  69. ->reverse()
  70. ->keys()
  71. ->first();

经验,要么不用,用了就用到底,不要因为纠结用不用浪费太多时间,一般这种情况,你都写不出来,最后使用 foreach 解决了。

关于 collection 的一切,都可以在这本书里找到,Never write loop again

Eloquent 在手,天下我有

应该是 php 世界里最好用的 orm,作者也说过整个框架最难写的地方就是 eloquent 了.

参考 app.php

OneToOne || OneToMany

  1. <?php
  2. namespace App;
  3. use Eloquent;
  4. class Post extends Eloquent
  5. {
  6. public function comments()
  7. {
  8. return $this->hasMany(Comment::class);
  9. }
  10. }
  1. public function show($id)
  2. {
  3. $post = Post::with('comments')->findOrFail($id); // 普通关联查询
  4. $post = Post::withCount('comments')->findOrFail($id); // 带上 count
  5. $post = Post::with([
  6. 'comments' => function ($q) {
  7. return $q->latest('create_time');
  8. }
  9. ])->findOrFail($id);
  10. }
  1. public function recentComments()
  2. {
  3. return $this->hasMany(Comment::class)
  4. ->where('created_at', '>', Carbon::yesterday());
  5. }
  1. public function scopeSince($query, $since, $column = 'created_at')
  2. {
  3. return $query->where($column, '>', $since);
  4. }
  5. public function scopeSinceYesterday($query)
  6. {
  7. return $this->since(Carbon::yesterday());
  8. }
  9. public function recentComments()
  10. {
  11. return $this->hasMany(Comment::class)->sinceYesterday();
  12. }

save comment?

  1. public function store(Request $request, Post $post)
  2. {
  3. // not to do like this!
  4. Comment::create([
  5. 'post_id' => $post->id,
  6. 'content' => 'wow!'
  7. ]);
  8. // here
  9. $post->comments()->create([
  10. 'content' => 'wow!'
  11. ]);
  12. }
  1. class Post
  2. {
  3. public function newComment($attributes)
  4. {
  5. return $this->comments()->create($attributes);
  6. }
  7. }

只有这样的写法才能叫 Eloquent.

BelongsTo || BelongsToMany

  1. class Post
  2. {
  3. public function author()
  4. {
  5. return $this->belongsTo(Author::class);
  6. }
  7. }
  1. class Post
  2. {
  3. public function newComment($author, $attributes)
  4. {
  5. $comment = new Comment($attributes);
  6. $comment->author()->associate($author);
  7. return $this->comments()->save($comment);
  8. }
  9. }

关于 eloquent 和 repository 的选择

这一直都是一个社区争论很多的话题

直接使用 eloquent

同时

添加 repository 层后

导致

整个应用生命周期

Eloquent

Millleware->Request->Controller->Eloquent->Response

Repository

Millleware->Request->Controller->Repository(Eloquent + Resquest)->Response

Eloquent 进阶

请食用 https://github.com/LingxiTeam/learn-eloquent 来进行深入实战学习。
目前内容并不太多,有时间都会抽空出来补充。

测试

Not jus TDD(Test-driven development), we want BDD(Behavior-driven development)

  1. class ExampleTestextendsTestCase
  2. {
  3. /**
  4. * A basic functional test example.
  5. * @return void
  6. */
  7. public function testBasicExample()
  8. {
  9. $this->visit('/')
  10. ->see('Laravel 5')
  11. ->dontSee('Rails');
  12. }
  13. }
  1. public function testSaveComment()
  2. {
  3. $comment = str_random(16);
  4. $this->post('/api/v1/comment', ['content' => $comment])
  5. ->seeJson([
  6. 'status_code' => '201',
  7. 'message' => 'Created.'
  8. ])
  9. ->seeInDatabase('comments', ['content' => $comment]);
  10. }

好的测试应该从 0 开始 (仅代表个人观点)

  1. $factory->define(App\Models\Team\Contact::class, function (Faker\Generator $faker) {
  2. $birthday = $faker->date();
  3. return [
  4. 'old_id' => mt_rand(100000, 999999),
  5. 'team_id' => 1024,
  6. 'name' => $faker->name,
  7. 'nickname' => $faker->username,
  8. 'email' => $faker->email,
  9. 'birthday' => $birthday,
  10. 'birth' => substr($birthday, -5),
  11. 'source' => 'create'
  12. ];
  13. });

ES6

Laravel 把 Vue 推向了世界,Vue 依赖于 ES6,加上 ES7 已经开始渐渐流行,你还不会 ES6?

所以, learn es6 by php.

var, let, const

在 es6 出来之前,javascript 是没有块级作用域这个概念的

  1. function goTop(currentHeight)
  2. {
  3. if (currentHeight > 100) {
  4. // go...
  5. var gone = true;
  6. console.log(gone);
  7. } else {
  8. console.log(gone);
  9. }
  10. }
  11. goTop(true); // true
  12. goTop(); // undefined, 对于 js 初学者,这里就很迷惑,Uncaught ReferenceError: gone is not defined
  13. function goTop(currentHeight)
  14. {
  15. var gone;
  16. if (currentHeight > 100) {
  17. // go...
  18. gone = true;
  19. console.log(gone);
  20. } else {
  21. console.log(gone);
  22. }
  23. }
  24. // in es6
  25. function goTop(currentHeight)
  26. {
  27. if (currentHeight > 100) {
  28. // go...
  29. let gone = true;
  30. console.log(gone);
  31. } else {
  32. console.log(gone);
  33. }
  34. }
  35. goTop(); Uncaught ReferenceError: gone is not defined

至于 const,也是一个块级作用域的声明,其他和 php 一样,不过在 es6 里,并不会大写

  1. const LANGUAGE = 'PHP';
  2. const language = 'javascript';

这里有个小坑

  1. const DATA = [1,2,3];
  2. DATA[] = 4; // PHP Fatal error: Cannot use [] for reading
  1. const data = [1,2,3];
  2. data.push(4); // [1,2,3,4]

Object.freeze

Arrow function

投票显示 es6 中最需要的功能

  1. var es5 = {
  2. go: function (a) {
  3. console.log(this)
  4. }
  5. }
  6. var es6 = {
  7. go: a => {
  8. console.log(this)
  9. }
  10. }
  11. // 区别在于箭头函数不会改变当前作用域,也就是 this.
  12. es6.go() // Window {speechSynthesis: ...}...
  13. es5.go() // Object {}
  14. es5.go.bind(this)() // Window {speechSynthesis: ...}...

默认参数

  1. function foo (a = 1) {
  2. console.log(a);
  3. }

解构

和 php 一样,很多语言都引入了这个特性, es6 更强大就是了

  1. function go (a, ...rest) {
  2. console.log(a, rest);
  3. }
  4. go (1,...[2,3,4]); // 1 [2, 3, 4]
  5. let obj = {
  6. a: 1,
  7. b: 2,
  8. c: 3
  9. }
  10. var a = obj.a;
  11. let {a, b, c} = obj;
  12. let {a, c} = obj;
  13. let {d} = obj; // undefined

Templete (模板字符串)

  1. const name = 'RryLee';
  2. console.log(`Hi!, i am ${name}`);
  3. // echo "Hi!, i am {$name}";

模板字符串还可以添加方法,可以自行了解

class

  1. class People {
  2. construct (age, name) {
  3. this.age = age;
  4. this.name = name;
  5. }
  6. say () {
  7. console.log(`I am ${name} and ${age} years old.`)
  8. }
  9. }
  1. class People
  2. {
  3. public function __construct (age, name) {
  4. $this->age = $age;
  5. $this->name = $name;
  6. }
  7. public function say() {
  8. echo 'I am ', name, ' and ', age, ' years old.'
  9. }
  10. }

模块化

  1. // util.js
  2. export function sum(a, b) {
  3. return a + b;
  4. }
  5. // client.js
  6. import { sum } from './util.js'
  7. console.log(sum(1, 3)) // 4
  8. // util.js
  9. export default function {
  10. console.log('I am default function.')
  11. }
  12. // client.js
  13. import say from './util'
  14. say() // I am default function.
  15. // more
  16. export default {}
  17. export const app_name = 'lingxi'
  18. export class User {}
  19. export ...

以上基本涵盖了 es6 的全部基础用法,关于更好玩的 (Promise, Generator...),当然是要自己去用了。Oh, 基础的还有 for-of(用于遍历数组,以及 es6 的数据解构, set, map 等1) 和 for-in (便利对象)

一个简单的迭代器实现 php 的 range() 方法

  1. function* range(start, end) {
  2. for (let i = start, j = 0; i <= end; i ++, j ++) {
  3. yield [i, j];
  4. }
  5. }
  6. for (let [num, i] of range(1, 10)) {
  7. console.log(`${i} => ${num}`);
  8. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注