
# 类工具函数

在模板中构建 `class` 属性时，需要拼接字符串、按条件切换类，并避免后添加的工具类与前面的工具类冲突（`p-2` 和 `p-4` 不应同时保留）。在 JavaScript 中，这项工作由 [clsx](https://github.com/lukeed/clsx) 和 [tailwind-merge](https://github.com/dcastil/tailwind-merge) 分担。TailwindPHP 提供两者的 PHP 移植版，让你无需 Node.js 工具链或额外的 Composer 包，也能获得相同的行为。

三个函数覆盖了不同需求：`cn()` 用于构建并消解冲突，`merge()` 仅用于消解冲突，`join()` 仅用于拼接。

## cn()

推荐使用的工具函数。它先按 clsx 风格进行条件构建，再通过 tailwind-merge 解决 Tailwind 冲突，因此最后一个冲突工具类会生效。

```php
use function TailwindPHP\cn;

// Conflicts are resolved — px-4 overrides px-2
cn('px-2 py-1', 'px-4');
// => 'py-1 px-4'

// Conditional classes via a key => bool array
cn('btn', ['btn-primary' => true, 'btn-disabled' => false]);
// => 'btn btn-primary'
```

### 接受的参数

`cn()` 接受任意数量的参数。每个参数都会按 clsx 语义展开并筛选：

| 参数 | 行为 |
|----------|----------|
| `string` | 按原样添加。 |
| `int` / `float` | 转换为字符串后添加。 |
| 顺序数组 | 递归处理每个元素。 |
| `key => bool` 数组 | 当值为真值时添加对应的键。 |
| `null`、`false`、`0`、`''` | 忽略。 |

```php
cn('flex', ['items-center' => true], ['p-4', ['gap-2']], null);
// => 'flex items-center p-4 gap-2'
```

### 组件模式

`cn()` 让组件可以被覆盖：将组件自身的类与调用方传入的类合并，发生冲突时以调用方为准。

```php
use function TailwindPHP\cn;

function Card(array $props = []): string {
    $class = cn(
        'rounded-lg border bg-card text-card-foreground shadow-sm',
        $props['class'] ?? null
    );
    return "<div class=\"{$class}\">" . ($props['children'] ?? '') . "</div>";
}

Card(['class' => 'p-6', 'children' => 'Content']);
// <div class="rounded-lg border bg-card text-card-foreground shadow-sm p-6">Content</div>
```

对于声明式、多轴的组件样式，可将 `cn()` 与 [variants()](https://tailwindphp.inline0.dev/zh/docs/class-utilities/variants) 配合使用。

## merge()

仅用于解决冲突，不进行条件构建。传入类字符串；如果后面的类与前面的类针对同一属性，后面的类会覆盖前面的类。适用于输入已经是普通字符串的情况。

```php
use function TailwindPHP\merge;

merge('px-2 py-1 bg-red-500', 'px-4 bg-blue-500');
// => 'py-1 px-4 bg-blue-500'

// Conflict resolution is variant-aware
merge('hover:bg-red-500', 'hover:bg-blue-500');
// => 'hover:bg-blue-500'
```

`cn()` 是基于 clsx 组合而成的 `merge()`，因此只有在不需要条件数组语法时，才直接使用 `merge()`。

## join()

只进行简单拼接，不解决冲突。假值会被丢弃，但相互冲突的工具类都会保留。确定没有冲突且希望开销最低时使用。

```php
use function TailwindPHP\join;

join('foo', 'bar', null, 'baz');
// => 'foo bar baz'
```

## 应该使用哪个？

| 函数 | 构建（条件、数组） | 解决冲突 | 适用情况 |
|----------|:---:|:---:|----------|
| `cn()` | 是 | 是 | 默认选择——构建可能存在冲突的类字符串。 |
| `merge()` | 否 | 是 | 输入是普通字符串，只需要消解冲突。 |
| `join()` | 是 | 否 | 确定没有冲突，且希望尽量减少处理。 |

## 导入

```php
use function TailwindPHP\cn;
use function TailwindPHP\merge;
use function TailwindPHP\join;
```

这三个函数都位于主 `TailwindPHP` 命名空间中，并随软件包一起打包。它们是 clsx（作者 Luke Edwards）和 tailwind-merge（作者 Dany Castillo）的 PHP 移植版。
