visifo/smack-clause 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

visifo/smack-clause

Composer 安装命令:

composer require visifo/smack-clause

包简介

SmackClause is a punchy, no-nonsense guard layer: it hits bad input fast, exits early, and leaves a clean trace of what failed, where, and why. The vibe is direct and a little aggressive, but the behavior is precise: stack small, composable rules, get strong default messages, and keep the happy path

README 文档

README

Latest Version on Packagist Tests Total Downloads

Fail fast. Speak clear. Stop bad input early.

SmackClause is a no-nonsense guard layer for PHP 8.5+. It hits bad input before it reaches your business logic, leaving a clean, structured trace of exactly what went wrong.

Why Smack?

  • Direct Assertions: No "should be" or "must be" fluff. Just isInt(), isEmail(), min().
  • Auto-Discovery: It knows your variable names. No more passing string labels manually.
  • PHP 8.5 Native: Built for the future with property hooks, asymmetric visibility, and high-performance tokenization.
  • Smart Nullability: Choose between a hard hit (that()) or a quiet pass (maybe()).

Installation

composer require visifo/smack-clause

Usage

The Hard Hit (Mandatory)

Smack::that() expects a value. If it's null or fails a rule, it smacks back.

Smack::that($email)->isString()->isEmail();
Smack::that($age)->isInt()->min(18);

The Quiet Pass (Optional)

Smack::maybe() allows nulls. If the value is there, it better be right.

Smack::maybe($bio)->isString()->max(200);

Hitting Collections

Smack::that($userIDs)->each()->isInt()->isPositive();

Allow Zero for Sign Checks

By default, isPositive() and isNegative() are strict (> 0 and < 0). Use allowZero() when you want zero to pass sign checks.

Smack::that($quantity)->isInt()->allowZero()->isPositive(); // allows 0 and positive ints
Smack::that($balance)->isInt()->allowZero()->isNegative(); // allows 0 and negative ints

Smack::that($price)->isFloat()->allowZero()->isPositive(); // allows 0.0 and positive floats
Smack::that($delta)->isFloat()->allowZero()->isNegative(); // allows 0.0 and negative floats

Custom Smacks

Extend the library with your own logic while keeping Smack::that(...)->... syntax.

use App\Smack\PlayerSmack;
use Visifo\SmackClause\Smack;

Smack::register(PlayerSmack::class);

Smack::that($player)
    ->isPlayer()
    ->isNotUn()
    ->isInPlayState();

You can register as many project-specific root methods as you need, one class at a time:

Smack::register(PlayerSmack::class);
Smack::register(VatSmack::class);

Use #[SmackMethod('...')] on the class and implement screenInto(...). Dynamic smack root methods do not accept arguments.

Option 1: Implement Smackable directly

use Visifo\SmackClause\Exceptions\SmackException;
use Visifo\SmackClause\Exceptions\Trace;
use Visifo\SmackClause\Extensions\SmackMethod;
use Visifo\SmackClause\Smackable;

#[SmackMethod('isVat')]
final readonly class VatSmack implements Smackable
{
    private function __construct(
        private VatId $vat,
        private Trace $trace,
    ) {}

    public static function screenInto(
        mixed $value,
        Trace $trace,
    ): self {
        if ($value instanceof VatId) {
            return new self($value, $trace);
        }

        throw SmackException::forExpectedType(VatId::class, $value, $trace);
    }

    public function isEu(): self
    {
        if ($this->vat->isEu()) {
            return $this;
        }

        throw SmackException::forConstraint('EU VAT ID', $this->vat, $this->trace);
    }
}

Option 2: Extend a typed smack (for method reuse)

If you extend ObjectSmack, always override screenInto(...) and call parent::__construct(...) to keep inherited object methods safe.

use Visifo\SmackClause\Exceptions\SmackException;
use Visifo\SmackClause\Exceptions\Trace;
use Visifo\SmackClause\Extensions\SmackMethod;
use Visifo\SmackClause\Types\ObjectSmack;

#[SmackMethod('isPlayer')]
final readonly class PlayerSmack extends ObjectSmack
{
    public function __construct(
        private GamePlayer $player,
        private Trace $trace,
    ) {
        parent::__construct($player, $trace);
    }

    public static function screenInto(mixed $value, Trace $trace): self
    {
        if ($value instanceof GamePlayer) {
            return new self($value, $trace);
        }

        throw SmackException::forExpectedType(GamePlayer::class, $value, $trace);
    }

    public function isNotUn(): self
    {
        if (! $this->player->isUn()) {
            return $this;
        }

        throw SmackException::forConstraint('not UN', $this->player, $this->trace);
    }
}

See tests/Fixtures/Smacks/PlayerSmack.php for a complete example.

IDE Helper

For dynamic custom methods (isPlayer(), isVat(), ...), generate a typed helper class for IDE/static tooling:

vendor/bin/smack-ide-helper

Available parameters:

  • --root=<path>
    • Default: current working directory (getcwd()).
    • Purpose: project root used for composer.json, autoload, and output file location.
  • --scan=<path>
    • Default: all autoload.psr-4 directories from <root>/composer.json.
    • Purpose: limit scanning to specific directory.
    • Notes: can be passed only once; when provided, it must point to a directory inside one of the root package's autoload.psr-4 directories.

This command generates _smack_ide_helper.php in your project root with a Visifo\\SmackClause\\IdeHelperSmack class that contains @method annotations for dynamic smack methods. Smack is linked to it via @mixin.

After generating, static tooling can understand calls like:

use Visifo\SmackClause\Smack;

Smack::that($player)
    ->isPlayer()
    ->isNotUn();

The generator is strict and fails if any registered smack class is invalid (missing #[SmackMethod('...')], duplicate method name, missing screenInto(...), inherited screenInto(...) without override, invalid class, etc.).

The Violation Report

When a check fails, SmackViolation (extends InvalidArgumentException) gives you the forensics:

  • Path: The variable or nested key name.
  • Value: What was actually received.
  • Rule: Which assertion failed.

Changelog

Please see CHANGELOG for more information on what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Branding & Tone Guide

TONE.md file ensures that anyone contributing to the project maintains the "Smack" vibe.

Security Vulnerabilities

Please review our security policy on how to report security vulnerabilities.

Credits

License

The MIT License (MIT). Please see License File for more information.

统计信息

  • 总下载量: 0
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 7
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-03-29

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固