Laravel thử bắt không hoạt động

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.

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

– Jason McCreary [@gonedark] ngày 1 tháng 6 năm 2020

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-macro

Trong 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];
        };
    }
}
3

Nế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];
        };
    }
}
3

collect[['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];
        };
    }
}
3

Chú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];
        };
    }
}
7

namespace 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];
        };
    }
}
5

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;
    }
}

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úng

namespace 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']
9

Mộ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ày

phiê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-macro

Tô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

Tôi có nên sử dụng thử bắt trong laravel không?

Không, bạn không cần khối try-catch . Như đã đề cập trong câu trả lời bên dưới, Laravel có hệ thống xử lý lỗi riêng nên bất kỳ ngoại lệ nào được ném ra sẽ bị Laravel bắt và báo cáo.

Thử bắt có bị chặn không?

Thử. câu lệnh bắt bao gồm khối thử và khối bắt, khối cuối cùng hoặc cả hai . Mã trong khối thử được thực thi trước và nếu nó đưa ra một ngoại lệ, mã trong khối bắt sẽ được thực thi.

Thử bắt có dừng thực thi không?

Đầu tiên, mã trong try {. } được thực thi. Nếu không có lỗi, thì bắt [err] được bỏ qua. quá trình thực thi kết thúc lần thử và tiếp tục, bỏ qua phần bắt. Nếu xảy ra lỗi, thì quá trình thực hiện thử sẽ bị dừng và điều khiển sẽ chuyển sang phần bắt đầu bắt [err].

Có try catch trong PHP không?

Phương pháp xử lý ngoại lệ chính trong PHP là bắt thử . Tóm lại, try-catch là một khối mã có thể được sử dụng để xử lý các ngoại lệ được ném ra mà không làm gián đoạn quá trình thực thi chương trình. Nói cách khác, bạn có thể "thử" thực thi một khối mã và "bắt" bất kỳ ngoại lệ PHP nào được đưa ra.

Chủ Đề