Vài tuần trước, Jmac đã tweet một ý tưởng tuyệt vời. Điều gì sẽ xảy ra nếu chúng ta có thể sử dụng
namespace Spatie\CollectionMacros\Macros;
use Spatie\CollectionMacros\Helpers\CatchableCollectionProxy;
class TryCatch
{
public function __invoke[]
{
return function [] {
return new CatchableCollectionProxy[$this];
};
}
}
2 và namespace Spatie\CollectionMacros\Macros;
use Spatie\CollectionMacros\Helpers\CatchableCollectionProxy;
class TryCatch
{
public function __invoke[]
{
return function [] {
return new CatchableCollectionProxy[$this];
};
}
}
3 trong chuỗi thu gom?Các bộ sưu tập rất thú vị. Tuy nhiên, họ để lại cho tôi mơ ước nhiều hơn nữa.
– Jason McCreary [@gonedark] ngày 1 tháng 6 năm 2020
Lấy khối này thực hiện một số logic xác thực tùy chỉnh bằng cách tận dụng hàm tạo đối tượng giá trị.
Các bộ sưu tập chắc chắn hợp lý hóa nó, nhưng nếu tôi cũng có thể xâu chuỗi việc xử lý ngoại lệ thì sao… 🔥 pic. Twitter. com/4jj0uFgwWb
Trong khi đó, Jmac và tôi đã thực hiện một vài phiên ghép mã để thực hiện triển khai khả thi. Chúng tôi đã thêm các phương thức
namespace Spatie\CollectionMacros\Macros;
use Spatie\CollectionMacros\Helpers\CatchableCollectionProxy;
class TryCatch
{
public function __invoke[]
{
return function [] {
return new CatchableCollectionProxy[$this];
};
}
}
2 và namespace Spatie\CollectionMacros\Macros;
use Spatie\CollectionMacros\Helpers\CatchableCollectionProxy;
class TryCatch
{
public function __invoke[]
{
return function [] {
return new CatchableCollectionProxy[$this];
};
}
}
3 vào gói laravel-collection-macroTrong bài đăng trên blog này, tôi muốn chia sẻ những gì bạn có thể làm với các phương pháp này và cách chúng hoạt động bí mật
Sử dụng try/catch trong chuỗi bộ sưu tập
Sau khi cài đặt laravel-collection-macro chứa , bạn có quyền truy cập vào các phương thức
namespace Spatie\CollectionMacros\Macros;
use Spatie\CollectionMacros\Helpers\CatchableCollectionProxy;
class TryCatch
{
public function __invoke[]
{
return function [] {
return new CatchableCollectionProxy[$this];
};
}
}
2 và namespace Spatie\CollectionMacros\Macros;
use Spatie\CollectionMacros\Helpers\CatchableCollectionProxy;
class TryCatch
{
public function __invoke[]
{
return function [] {
return new CatchableCollectionProxy[$this];
};
}
}
3Nếu bất kỳ phương pháp nào giữa
namespace Spatie\CollectionMacros\Macros;
use Spatie\CollectionMacros\Helpers\CatchableCollectionProxy;
class TryCatch
{
public function __invoke[]
{
return function [] {
return new CatchableCollectionProxy[$this];
};
}
}
2 và namespace Spatie\CollectionMacros\Macros;
use Spatie\CollectionMacros\Helpers\CatchableCollectionProxy;
class TryCatch
{
public function __invoke[]
{
return function [] {
return new CatchableCollectionProxy[$this];
};
}
}
3 đưa ra một ngoại lệ, thì ngoại lệ đó có thể được xử lý trong namespace Spatie\CollectionMacros\Macros;
use Spatie\CollectionMacros\Helpers\CatchableCollectionProxy;
class TryCatch
{
public function __invoke[]
{
return function [] {
return new CatchableCollectionProxy[$this];
};
}
}
3collect[['a', 'b', 'c', 1, 2, 3]]
->try[]
->map[fn [$letter] => strtoupper[$letter]]
->each[function[] {
throw new Exception['Explosions in the sky'];
}]
->catch[function [Exception $exception] {
// handle exception here
}]
->map[function[] {
// further operations can be done, if the exception wasn't rethrow in the `catch`
}];
Mặc dù các phương thức được đặt tên là
namespace Spatie\CollectionMacros\Macros;
use Spatie\CollectionMacros\Helpers\CatchableCollectionProxy;
class TryCatch
{
public function __invoke[]
{
return function [] {
return new CatchableCollectionProxy[$this];
};
}
}
2/namespace Spatie\CollectionMacros\Macros;
use Spatie\CollectionMacros\Helpers\CatchableCollectionProxy;
class TryCatch
{
public function __invoke[]
{
return function [] {
return new CatchableCollectionProxy[$this];
};
}
}
3 để làm quen với PHP, nhưng bản thân bộ sưu tập hoạt động giống như một giao dịch cơ sở dữ liệu hơn. Vì vậy, khi một ngoại lệ được đưa ra, bộ sưu tập ban đầu [trước namespace Spatie\CollectionMacros\Macros;
use Spatie\CollectionMacros\Helpers\CatchableCollectionProxy;
class TryCatch
{
public function __invoke[]
{
return function [] {
return new CatchableCollectionProxy[$this];
};
}
}
2] được trả vềBạn có thể có quyền truy cập vào bộ sưu tập trong phần bắt bằng cách thêm tham số thứ hai vào trình xử lý của mình. Bạn cũng có thể thao tác bộ sưu tập trong catch bằng cách trả về một giá trị
$collection = collect[['a', 'b', 'c', 1, 2, 3]]
->try[]
->map[function [$item] {
throw new Exception[];
}]
->catch[function [Exception $exception, $collection] {
return collect[['d', 'e', 'f']];
}]
->map[function [$item] {
return strtoupper[$item];
}];
// ['D', 'E', 'F']
Làm thế nào các phương pháp hoạt động trên dưới mui xe
Để
namespace Spatie\CollectionMacros\Macros;
use Spatie\CollectionMacros\Helpers\CatchableCollectionProxy;
class TryCatch
{
public function __invoke[]
{
return function [] {
return new CatchableCollectionProxy[$this];
};
}
}
2/namespace Spatie\CollectionMacros\Macros;
use Spatie\CollectionMacros\Helpers\CatchableCollectionProxy;
class TryCatch
{
public function __invoke[]
{
return function [] {
return new CatchableCollectionProxy[$this];
};
}
}
3 hoạt động, chúng tôi cần một cách để không thực hiện ngay các lệnh gọi phương thức sau namespace Spatie\CollectionMacros\Macros;
use Spatie\CollectionMacros\Helpers\CatchableCollectionProxy;
class TryCatch
{
public function __invoke[]
{
return function [] {
return new CatchableCollectionProxy[$this];
};
}
}
2. Nếu chúng được thực thi ngay lập tức, chúng ta sẽ không có cách nào bắt được các ngoại lệ mà các phương thức này có thể ném ra. Các phương thức giữa namespace Spatie\CollectionMacros\Macros;
use Spatie\CollectionMacros\Helpers\CatchableCollectionProxy;
class TryCatch
{
public function __invoke[]
{
return function [] {
return new CatchableCollectionProxy[$this];
};
}
}
2 và namespace Spatie\CollectionMacros\Macros;
use Spatie\CollectionMacros\Helpers\CatchableCollectionProxy;
class TryCatch
{
public function __invoke[]
{
return function [] {
return new CatchableCollectionProxy[$this];
};
}
}
3 nên được thực hiện khi đạt tới namespace Spatie\CollectionMacros\Macros;
use Spatie\CollectionMacros\Helpers\CatchableCollectionProxy;
class TryCatch
{
public function __invoke[]
{
return function [] {
return new CatchableCollectionProxy[$this];
};
}
}
3Chúng tôi đã giải quyết vấn đề này bằng cách để
namespace Spatie\CollectionMacros\Macros;
use Spatie\CollectionMacros\Helpers\CatchableCollectionProxy;
class TryCatch
{
public function __invoke[]
{
return function [] {
return new CatchableCollectionProxy[$this];
};
}
}
2 không trả về một bộ sưu tập thực mà là một thể hiện của một lớp khác có tên là namespace Spatie\CollectionMacros\Macros;
use Spatie\CollectionMacros\Helpers\CatchableCollectionProxy;
class TryCatch
{
public function __invoke[]
{
return function [] {
return new CatchableCollectionProxy[$this];
};
}
}
5. Điều này được thực hiện trong lớp namespace Spatie\CollectionMacros\Macros;
use Spatie\CollectionMacros\Helpers\CatchableCollectionProxy;
class TryCatch
{
public function __invoke[]
{
return function [] {
return new CatchableCollectionProxy[$this];
};
}
}
6, lớp này trả về một hàm có thể gọi được đóng vai trò triển khai macro namespace Spatie\CollectionMacros\Macros;
use Spatie\CollectionMacros\Helpers\CatchableCollectionProxy;
class TryCatch
{
public function __invoke[]
{
return function [] {
return new CatchableCollectionProxy[$this];
};
}
}
7namespace Spatie\CollectionMacros\Macros;
use Spatie\CollectionMacros\Helpers\CatchableCollectionProxy;
class TryCatch
{
public function __invoke[]
{
return function [] {
return new CatchableCollectionProxy[$this];
};
}
}
Với điều này tại chỗ,
namespace Spatie\CollectionMacros\Macros;
use Spatie\CollectionMacros\Helpers\CatchableCollectionProxy;
class TryCatch
{
public function __invoke[]
{
return function [] {
return new CatchableCollectionProxy[$this];
};
}
}
2 trả về một thể hiện của namespace Spatie\CollectionMacros\Macros;
use Spatie\CollectionMacros\Helpers\CatchableCollectionProxy;
class TryCatch
{
public function __invoke[]
{
return function [] {
return new CatchableCollectionProxy[$this];
};
}
}
5$collection = collect[['a', 'b', 'c', 1, 2, 3]]
->try[] // returns `CatchableCollectionProxy`
->map[] // will be called on the catchable collection proxy
->catch[] // will be called on the catchable collection proxy
-> ...
Chúng ta hãy xem việc triển khai
namespace Spatie\CollectionMacros\Macros;
use Spatie\CollectionMacros\Helpers\CatchableCollectionProxy;
class TryCatch
{
public function __invoke[]
{
return function [] {
return new CatchableCollectionProxy[$this];
};
}
}
5namespace Spatie\CollectionMacros\Helpers;
use Closure;
use Illuminate\Support\Enumerable;
use ReflectionFunction;
use Throwable;
/**
* @mixin \Illuminate\Support\Enumerable
*/
class CatchableCollectionProxy
{
protected Enumerable $collection;
protected array $calledMethods = [];
public function __construct[Enumerable $collection]
{
$this->collection = $collection;
}
public function __call[string $method, array $parameters]: self
{
$this->calledMethods[] = ['name' => $method, 'parameters' => $parameters];
return $this;
}
public function catch[Closure ...$handlers]: Enumerable
{
$originalCollection = $this->collection;
try {
foreach [$this->calledMethods as $calledMethod] {
$this->collection = $this->collection->{$calledMethod['name']}[...$calledMethod['parameters']];
}
} catch [Throwable $exception] {
foreach [$handlers as $callable] {
$type = $this->exceptionType[$callable];
if [$exception instanceof $type] {
return $callable[$exception, $originalCollection] ?? $originalCollection;
}
}
throw $exception;
}
return $this->collection;
}
private function exceptionType[Closure $callable]: string
{
$reflection = new ReflectionFunction[$callable];
if [empty[$reflection->getParameters[]]] {
return Throwable::class;
}
return optional[$reflection->getParameters[][0]->getType[]]->getName[] ?? Throwable::class;
}
}
Hãy mổ xẻ. Lớp proxy này có phương thức
$collection = collect[['a', 'b', 'c', 1, 2, 3]]
->try[] // returns `CatchableCollectionProxy`
->map[] // will be called on the catchable collection proxy
->catch[] // will be called on the catchable collection proxy
-> ...
1. Phương thức ma thuật này sẽ được thực thi cho mỗi cuộc gọi đến lớp này mà không tồn tại một triển khai. Vì vậy, nếu bạn gọi ví dụ $collection = collect[['a', 'b', 'c', 1, 2, 3]]
->try[] // returns `CatchableCollectionProxy`
->map[] // will be called on the catchable collection proxy
->catch[] // will be called on the catchable collection proxy
-> ...
2 trên một phiên bản của namespace Spatie\CollectionMacros\Macros;
use Spatie\CollectionMacros\Helpers\CatchableCollectionProxy;
class TryCatch
{
public function __invoke[]
{
return function [] {
return new CatchableCollectionProxy[$this];
};
}
}
5, thì $collection = collect[['a', 'b', 'c', 1, 2, 3]]
->try[] // returns `CatchableCollectionProxy`
->map[] // will be called on the catchable collection proxy
->catch[] // will be called on the catchable collection proxy
-> ...
1 sẽ được thực thi. Nó sẽ nhận "bản đồ" trong đối số $collection = collect[['a', 'b', 'c', 1, 2, 3]]
->try[] // returns `CatchableCollectionProxy`
->map[] // will be called on the catchable collection proxy
->catch[] // will be called on the catchable collection proxy
-> ...
5, tất cả các tham số bạn cung cấp cho phương thức trong $collection = collect[['a', 'b', 'c', 1, 2, 3]]
->try[] // returns `CatchableCollectionProxy`
->map[] // will be called on the catchable collection proxy
->catch[] // will be called on the catchable collection proxy
-> ...
6. Chúng tôi sẽ giữ cả hai phần thông tin trong mảng $collection = collect[['a', 'b', 'c', 1, 2, 3]]
->try[] // returns `CatchableCollectionProxy`
->map[] // will be called on the catchable collection proxy
->catch[] // will be called on the catchable collection proxy
-> ...
7. Về cơ bản, chúng tôi theo dõi phương thức nào được gọi trên proxy mà không thực thi chúngnamespace Spatie\CollectionMacros\Macros;
use Spatie\CollectionMacros\Helpers\CatchableCollectionProxy;
class TryCatch
{
public function __invoke[]
{
return function [] {
return new CatchableCollectionProxy[$this];
};
}
}
5 có một phương thức thực gọi là. namespace Spatie\CollectionMacros\Macros;
use Spatie\CollectionMacros\Helpers\CatchableCollectionProxy;
class TryCatch
{
public function __invoke[]
{
return function [] {
return new CatchableCollectionProxy[$this];
};
}
}
3. Khi phương thức này được gọi, nó sẽ duyệt qua tất cả các mục trong $collection = collect[['a', 'b', 'c', 1, 2, 3]]
->try[] // returns `CatchableCollectionProxy`
->map[] // will be called on the catchable collection proxy
->catch[] // will be called on the catchable collection proxy
-> ...
7 và sử dụng thông tin được lưu trữ đểVòng lặp này đang được thực hiện trong. Nếu bất kỳ phương thức nào được gọi là ném ngoại lệ, chúng tôi. Ngoại lệ sẽ là
Và đó là tất cả để có nó
Có thêm một mẩu tin thú vị để xem xét. Trong các trường hợp bình thường, các IDE sẽ không thể tự động hoàn thành các phương thức thu thập nữa sau phương thức
namespace Spatie\CollectionMacros\Macros;
use Spatie\CollectionMacros\Helpers\CatchableCollectionProxy;
class TryCatch
{
public function __invoke[]
{
return function [] {
return new CatchableCollectionProxy[$this];
};
}
}
2. phương thức namespace Spatie\CollectionMacros\Macros;
use Spatie\CollectionMacros\Helpers\CatchableCollectionProxy;
class TryCatch
{
public function __invoke[]
{
return function [] {
return new CatchableCollectionProxy[$this];
};
}
}
2 trả về một đối tượng chỉ với việc triển khai namespace Spatie\CollectionMacros\Macros;
use Spatie\CollectionMacros\Helpers\CatchableCollectionProxy;
class TryCatch
{
public function __invoke[]
{
return function [] {
return new CatchableCollectionProxy[$this];
};
}
}
3Điều này được giải quyết bằng cách đứng đầu lớp
$collection = collect[['a', 'b', 'c', 1, 2, 3]]
->try[]
->map[function [$item] {
throw new Exception[];
}]
->catch[function [Exception $exception, $collection] {
return collect[['d', 'e', 'f']];
}]
->map[function [$item] {
return strtoupper[$item];
}];
// ['D', 'E', 'F']
9Một
namespace Spatie\CollectionMacros\Helpers;
use Closure;
use Illuminate\Support\Enumerable;
use ReflectionFunction;
use Throwable;
/**
* @mixin \Illuminate\Support\Enumerable
*/
class CatchableCollectionProxy
{
protected Enumerable $collection;
protected array $calledMethods = [];
public function __construct[Enumerable $collection]
{
$this->collection = $collection;
}
public function __call[string $method, array $parameters]: self
{
$this->calledMethods[] = ['name' => $method, 'parameters' => $parameters];
return $this;
}
public function catch[Closure ...$handlers]: Enumerable
{
$originalCollection = $this->collection;
try {
foreach [$this->calledMethods as $calledMethod] {
$this->collection = $this->collection->{$calledMethod['name']}[...$calledMethod['parameters']];
}
} catch [Throwable $exception] {
foreach [$handlers as $callable] {
$type = $this->exceptionType[$callable];
if [$exception instanceof $type] {
return $callable[$exception, $originalCollection] ?? $originalCollection;
}
}
throw $exception;
}
return $this->collection;
}
private function exceptionType[Closure $callable]: string
{
$reflection = new ReflectionFunction[$callable];
if [empty[$reflection->getParameters[]]] {
return Throwable::class;
}
return optional[$reflection->getParameters[][0]->getType[]]->getName[] ?? Throwable::class;
}
}
6 docblock gợi ý cho một IDE rằng mọi phương thức có sẵn trên lớp được đề cập trong docblock, cũng có sẵn trên lớp mà docblock áp dụng cho. Nếu bạn muốn tìm hiểu thêm về khối tài liệu namespace Spatie\CollectionMacros\Helpers;
use Closure;
use Illuminate\Support\Enumerable;
use ReflectionFunction;
use Throwable;
/**
* @mixin \Illuminate\Support\Enumerable
*/
class CatchableCollectionProxy
{
protected Enumerable $collection;
protected array $calledMethods = [];
public function __construct[Enumerable $collection]
{
$this->collection = $collection;
}
public function __call[string $method, array $parameters]: self
{
$this->calledMethods[] = ['name' => $method, 'parameters' => $parameters];
return $this;
}
public function catch[Closure ...$handlers]: Enumerable
{
$originalCollection = $this->collection;
try {
foreach [$this->calledMethods as $calledMethod] {
$this->collection = $this->collection->{$calledMethod['name']}[...$calledMethod['parameters']];
}
} catch [Throwable $exception] {
foreach [$handlers as $callable] {
$type = $this->exceptionType[$callable];
if [$exception instanceof $type] {
return $callable[$exception, $originalCollection] ?? $originalCollection;
}
}
throw $exception;
}
return $this->collection;
}
private function exceptionType[Closure $callable]: string
{
$reflection = new ReflectionFunction[$callable];
if [empty[$reflection->getParameters[]]] {
return Throwable::class;
}
return optional[$reflection->getParameters[][0]->getType[]]->getName[] ?? Throwable::class;
}
}
6, hãy đọc bài đăng trên blog nàyphiên phát trực tuyến
Như đã đề cập trong phần giới thiệu, Jmac và tôi đã cùng nhau tạo ra các macro này. Chúng tôi đã phát trực tuyến tất cả các phiên của chúng tôi. Bạn có thể xem các đoạn ghi âm dưới đây
Trong phiên đầu tiên, Jmac và tôi đã mã hóa giải pháp
Trong phiên tiếp theo, chúng tôi đã xem lại mã được đánh bóng và kiểm tra
Trong phiên cuối cùng, chúng tôi đã thêm các phương thức
namespace Spatie\CollectionMacros\Macros;
use Spatie\CollectionMacros\Helpers\CatchableCollectionProxy;
class TryCatch
{
public function __invoke[]
{
return function [] {
return new CatchableCollectionProxy[$this];
};
}
}
2/namespace Spatie\CollectionMacros\Macros;
use Spatie\CollectionMacros\Helpers\CatchableCollectionProxy;
class TryCatch
{
public function __invoke[]
{
return function [] {
return new CatchableCollectionProxy[$this];
};
}
}
3 dưới dạng macro trong gói laravel-collection-macroTôi rất thích thực hiện các phiên mã hóa này với Jmac và tôi hy vọng tôi có thể làm được nhiều điều hơn nữa với anh ấy trong tương lai
kết thúc
Các phương pháp
namespace Spatie\CollectionMacros\Macros;
use Spatie\CollectionMacros\Helpers\CatchableCollectionProxy;
class TryCatch
{
public function __invoke[]
{
return function [] {
return new CatchableCollectionProxy[$this];
};
}
}
2/namespace Spatie\CollectionMacros\Macros;
use Spatie\CollectionMacros\Helpers\CatchableCollectionProxy;
class TryCatch
{
public function __invoke[]
{
return function [] {
return new CatchableCollectionProxy[$this];
};
}
}
3 sẽ hữu ích trong nhiều tình huống. Tôi hy vọng rằng một ngày nào đó, các phương thức này sẽ có sẵn trong chính Laravel. Cho đến lúc đó, hãy cài đặt gói laravel-collection-macro để sử dụng chúng