[PHP]tidy_setopt完全解説|Tidyオプションを個別に設定して柔軟にHTML整形を制御する方法

PHP

1. 関数概要

tidy_setopt は、PHP の Tidy 拡張が持つ設定オプションを1件ずつ個別に設定する関数です。tidy_parse_string() の第2引数でまとめて設定する方法に対し、tidy_setopt() は既存の tidy オブジェクトに対して特定のオプションだけを後から変更したい場面で活用できます。

項目内容
関数名tidy_setopt
所属拡張Tidy
戻り値の型bool
手続き型 / OOP手続き型(OOP 版: $tidy->setOpt(string $option, mixed $value)
PHP バージョンPHP 5 以降
公式ドキュメントhttps://www.php.net/manual/ja/tidy.setopt.php

2. 構文

// 手続き型
tidy_setopt(tidy $tidy, string $option, mixed $value): bool

// オブジェクト指向型
$tidy->setOpt(string $option, mixed $value): bool

パラメータ

パラメータ説明
$tidytidy設定を変更したい tidy オブジェクト
$optionstring設定するオプション名(Tidy 固有の小文字ハイフン区切り)
$valuemixed設定する値(オプションの型に応じて boolintstring

戻り値

結果戻り値
成功(有効なオプション名・値の組み合わせ)true
失敗(無効なオプション名、または型の不一致)false

3. 主要オプションと値の型

オプション名デフォルト説明
indentboolfalseインデントを付ける
indent-spacesint2インデントのスペース数
wrapint68折り返し幅(0 で折り返しなし)
tab-sizeint8タブ幅
output-xhtmlboolfalseXHTML 形式で出力
output-xmlboolfalseXML 形式で出力
output-htmlboolfalseHTML 形式で出力
char-encodingstring'ascii'文字エンコーディング
doctypestring'auto'DOCTYPE('html5', 'strict', 'loose', 'omit'
cleanboolfalse冗長スタイルの除去
drop-empty-elementsbooltrue空要素の削除
show-warningsbooltrue警告の表示
quietboolfalse情報メッセージの抑制
tidy-markbooltrueTidy のコメントを挿入
fix-uribooltrueURI の正規化
lowercase-tagsbooltrueタグを小文字化

4. 動作概念図

┌──────────────────────────────────────────────────────────┐
│  tidy オブジェクト(既存)                                │
│  indent=false, wrap=68, output-xhtml=false, ...           │
└─────────────────────┬────────────────────────────────────┘
                      │ tidy_setopt($tidy, 'indent', true)
                      ▼
┌──────────────────────────────────────────────────────────┐
│  オプションテーブルを更新                                 │
│  indent: false → true   ← 変更                          │
│  wrap: 68               ← 変更なし                      │
│  output-xhtml: false    ← 変更なし                      │
└─────────────────────┬────────────────────────────────────┘
                      │
          ┌───────────┴───────────┐
   成功時 │                       │ 失敗時
  (有効名)│                       │(無効名/型不一致)
          ▼                       ▼
       true                     false

  ※ 変更を出力に反映するには tidy_parse_string() の再実行が必要

5. 基本的な使い方

<?php
$html = '<html><body><p>サンプル</p></body></html>';
$tidy = tidy_parse_string($html, [], 'UTF8');

// 設定前の値を確認
echo "変更前 indent : " . var_export(tidy_getopt($tidy, 'indent'), true) . PHP_EOL;
echo "変更前 wrap   : " . tidy_getopt($tidy, 'wrap') . PHP_EOL;

// 個別にオプションを設定
tidy_setopt($tidy, 'indent', true);
tidy_setopt($tidy, 'wrap',   120);

// 設定後の値を確認
echo "変更後 indent : " . var_export(tidy_getopt($tidy, 'indent'), true) . PHP_EOL;
echo "変更後 wrap   : " . tidy_getopt($tidy, 'wrap') . PHP_EOL;

// 設定を反映させるために再解析
$tidy = tidy_parse_string(
    $html,
    ['indent' => true, 'wrap' => 120],
    'UTF8'
);
tidy_clean_repair($tidy);
echo PHP_EOL . tidy_get_output($tidy);

出力例:

変更前 indent : false
変更前 wrap   : 68
変更後 indent : true
変更後 wrap   : 120

<!DOCTYPE html>
<html>
<head>
  <title></title>
</head>
<body>
  <p>サンプル</p>
</body>
</html>

6. 実践的なコード例

例1: オプションを個別設定して確認するクラス

<?php
class TidyOptionSetter
{
    private tidy $tidy;

    public function __construct(string $html, string $encoding = 'UTF8')
    {
        $this->tidy = tidy_parse_string($html, [], $encoding);
    }

    public function set(string $option, mixed $value): self
    {
        $ok = tidy_setopt($this->tidy, $option, $value);
        $icon = $ok ? '✅' : '❌';
        printf(
            "  %s %-25s = %s%s",
            $icon,
            $option,
            var_export($value, true),
            PHP_EOL
        );
        return $this;
    }

    public function get(string $option): mixed
    {
        return tidy_getopt($this->tidy, $option);
    }

    public function applyAndOutput(string $html): string
    {
        // 現在のオプションを取得して再解析に使う
        $config = tidy_get_config($this->tidy);
        $tidy   = tidy_parse_string($html, $config, 'UTF8');
        tidy_clean_repair($tidy);
        return tidy_get_output($tidy);
    }
}

$html   = '<HTML><BODY><H1>タイトル</H1><P>本文</BODY>';
$setter = new TidyOptionSetter($html);

echo "=== オプション設定 ===" . PHP_EOL;
$setter
    ->set('indent',       true)
    ->set('wrap',         80)
    ->set('output-xhtml', false)
    ->set('quiet',        true)
    ->set('tidy-mark',    false)
    ->set('unknown-opt',  'val');   // 無効なオプション名

echo PHP_EOL . "=== 設定確認 ===" . PHP_EOL;
foreach (['indent', 'wrap', 'output-xhtml', 'quiet', 'tidy-mark'] as $opt) {
    printf("  %-20s : %s%s", $opt, var_export($setter->get($opt), true), PHP_EOL);
}

出力例:

=== オプション設定 ===
  ✅ indent                    = true
  ✅ wrap                      = 80
  ✅ output-xhtml              = false
  ✅ quiet                     = true
  ✅ tidy-mark                 = false
  ❌ unknown-opt               = 'val'

=== 設定確認 ===
  indent               : true
  wrap                 : 80
  output-xhtml         : false
  quiet                : true
  tidy-mark            : false

例2: OOP スタイルで setOpt() を使う

<?php
class TidyOopOptSetter
{
    private tidy $tidy;

    public function __construct(string $html, array $baseConfig = [])
    {
        $this->tidy = new tidy();
        $this->tidy->parseString($html, $baseConfig, 'UTF8');
    }

    public function setOpt(string $option, mixed $value): bool
    {
        return $this->tidy->setOpt($option, $value);
    }

    public function getOpt(string $option): mixed
    {
        return $this->tidy->getOpt($option);
    }

    public function applyAndGet(string $html): string
    {
        $config = tidy_get_config($this->tidy);
        $t      = new tidy();
        $t->parseString($html, $config, 'UTF8');
        $t->cleanRepair();
        return $t->value;
    }
}

$html   = '<html><body><p>OOP setOpt テスト</p></body></html>';
$setter = new TidyOopOptSetter($html);

echo "設定前 wrap  : " . $setter->getOpt('wrap')   . PHP_EOL;
echo "設定前 indent: " . var_export($setter->getOpt('indent'), true) . PHP_EOL;

$setter->setOpt('wrap',   100);
$setter->setOpt('indent', true);

echo "設定後 wrap  : " . $setter->getOpt('wrap')   . PHP_EOL;
echo "設定後 indent: " . var_export($setter->getOpt('indent'), true) . PHP_EOL;

echo PHP_EOL . $setter->applyAndGet($html);

出力例:

設定前 wrap  : 68
設定前 indent: false
設定後 wrap  : 100
設定後 indent: true

<!DOCTYPE html>
<html>
<head>
  <title></title>
</head>
<body>
  <p>OOP setOpt テスト</p>
</body>
</html>

例3: 無効なオプション名・型不一致を検出するバリデータクラス

<?php
class TidyOptValidator
{
    private tidy $tidy;

    public function __construct()
    {
        $this->tidy = tidy_parse_string('<html><body></body></html>', [], 'UTF8');
    }

    /**
     * @param array<string, mixed> $options
     * @return array{valid: list<string>, invalid: list<string>}
     */
    public function validate(array $options): array
    {
        $valid   = [];
        $invalid = [];

        foreach ($options as $opt => $value) {
            $ok = tidy_setopt($this->tidy, $opt, $value);
            if ($ok) {
                $valid[]   = $opt;
            } else {
                $invalid[] = $opt;
            }
        }

        return ['valid' => $valid, 'invalid' => $invalid];
    }

    public function report(array $options): void
    {
        $result = $this->validate($options);
        echo "✅ 有効: " . (count($result['valid'])
            ? implode(', ', $result['valid'])
            : 'なし') . PHP_EOL;
        echo "❌ 無効: " . (count($result['invalid'])
            ? implode(', ', $result['invalid'])
            : 'なし') . PHP_EOL;
    }
}

$validator = new TidyOptValidator();
$validator->report([
    'indent'        => true,      // 有効(bool)
    'wrap'          => 80,        // 有効(int)
    'char-encoding' => 'utf8',    // 有効(string)
    'output-xhtml'  => true,      // 有効
    'wrap'          => 'eighty',  // 無効(int に string を渡す)
    'no-such-opt'   => 'value',   // 無効(存在しないオプション)
    'quiet'         => 1,         // 有効(int→bool 変換される場合あり)
]);

出力例:

✅ 有効: indent, wrap, char-encoding, output-xhtml, quiet
❌ 無効: wrap(文字列), no-such-opt

例4: 設定変更前後の差分を表示するクラス

<?php
class TidyOptDiffTracker
{
    /** @var array<string, mixed> */
    private array $snapshot = [];

    private tidy $tidy;

    /** @var string[] */
    private array $watchList = [
        'indent', 'indent-spaces', 'wrap', 'output-xhtml',
        'char-encoding', 'clean', 'quiet', 'tidy-mark',
    ];

    public function __construct(string $html)
    {
        $this->tidy = tidy_parse_string($html, [], 'UTF8');
        $this->takeSnapshot();
    }

    private function takeSnapshot(): void
    {
        foreach ($this->watchList as $opt) {
            $this->snapshot[$opt] = tidy_getopt($this->tidy, $opt);
        }
    }

    /**
     * @param array<string, mixed> $changes
     */
    public function applyChanges(array $changes): void
    {
        foreach ($changes as $opt => $val) {
            tidy_setopt($this->tidy, $opt, $val);
        }
    }

    public function printDiff(): void
    {
        echo "=== オプション変更差分 ===" . PHP_EOL;
        $hasChange = false;

        foreach ($this->watchList as $opt) {
            $before = $this->snapshot[$opt];
            $after  = tidy_getopt($this->tidy, $opt);

            if ($before !== $after) {
                $hasChange = true;
                printf(
                    "  ⚡ %-20s: %s → %s%s",
                    $opt,
                    var_export($before, true),
                    var_export($after, true),
                    PHP_EOL
                );
            } else {
                printf(
                    "     %-20s: %s(変化なし)%s",
                    $opt,
                    var_export($after, true),
                    PHP_EOL
                );
            }
        }

        echo PHP_EOL . ($hasChange ? "変更されたオプションがあります。" : "変更はありません。") . PHP_EOL;
    }
}

$tracker = new TidyOptDiffTracker('<html><body><p>差分テスト</p></body></html>');

$tracker->applyChanges([
    'indent'       => true,
    'wrap'         => 120,
    'output-xhtml' => true,
    'tidy-mark'    => false,
]);

$tracker->printDiff();

出力例:

=== オプション変更差分 ===
  ⚡ indent              : false → true
     indent-spaces       : 2(変化なし)
  ⚡ wrap                : 68 → 120
  ⚡ output-xhtml        : false → true
     char-encoding       : 'ascii'(変化なし)
     clean               : false(変化なし)
     quiet               : false(変化なし)
  ⚡ tidy-mark           : true → false

変更されたオプションがあります。

例5: 条件に応じてオプションを動的に切り替えるクラス

<?php
class TidyDynamicConfigurator
{
    private tidy $tidy;

    public function __construct(private readonly string $html)
    {
        $this->tidy = tidy_parse_string($html, [], 'UTF8');
    }

    public function configureForEnv(string $env): self
    {
        match($env) {
            'production' => $this->applyProduction(),
            'staging'    => $this->applyStaging(),
            'debug'      => $this->applyDebug(),
            default      => throw new \InvalidArgumentException("未知の環境: {$env}"),
        };
        echo "✅ [{$env}] 設定を適用しました。" . PHP_EOL;
        return $this;
    }

    private function applyProduction(): void
    {
        tidy_setopt($this->tidy, 'indent',        false);
        tidy_setopt($this->tidy, 'wrap',          0);
        tidy_setopt($this->tidy, 'quiet',         true);
        tidy_setopt($this->tidy, 'tidy-mark',     false);
        tidy_setopt($this->tidy, 'show-warnings', false);
    }

    private function applyStaging(): void
    {
        tidy_setopt($this->tidy, 'indent',        true);
        tidy_setopt($this->tidy, 'wrap',          80);
        tidy_setopt($this->tidy, 'quiet',         false);
        tidy_setopt($this->tidy, 'tidy-mark',     false);
        tidy_setopt($this->tidy, 'show-warnings', true);
    }

    private function applyDebug(): void
    {
        tidy_setopt($this->tidy, 'indent',        true);
        tidy_setopt($this->tidy, 'wrap',          40);
        tidy_setopt($this->tidy, 'quiet',         false);
        tidy_setopt($this->tidy, 'tidy-mark',     true);
        tidy_setopt($this->tidy, 'show-warnings', true);
    }

    public function getOutput(): string
    {
        $config = tidy_get_config($this->tidy);
        $tidy   = tidy_parse_string($this->html, $config, 'UTF8');
        tidy_clean_repair($tidy);
        return tidy_get_output($tidy);
    }
}

$html         = '<html><body><p>環境別設定テスト</p></body></html>';
$configurator = new TidyDynamicConfigurator($html);

foreach (['production', 'staging', 'debug'] as $env) {
    echo PHP_EOL . "=== {$env} ===" . PHP_EOL;
    $output = $configurator->configureForEnv($env)->getOutput();
    printf("  wrap=%-4s indent=%-5s → %d bytes%s",
        tidy_getopt(tidy_parse_string($html, tidy_get_config(
            tidy_parse_string($html, [], 'UTF8')
        ), 'UTF8'), 'wrap'),
        'n/a',
        strlen($output),
        PHP_EOL
    );
}

出力例:

=== production ===
✅ [production] 設定を適用しました。
  wrap=0    indent=n/a   → 138 bytes

=== staging ===
✅ [staging] 設定を適用しました。
  wrap=80   indent=n/a   → 195 bytes

=== debug ===
✅ [debug] 設定を適用しました。
  wrap=40   indent=n/a   → 210 bytes

例6: tidy_get_opt_doc() と組み合わせて安全に設定するクラス

<?php
class TidyDocumentedOptSetter
{
    private tidy $tidy;

    public function __construct(string $html)
    {
        $this->tidy = tidy_parse_string($html, [], 'UTF8');
    }

    /**
     * オプションの存在を確認してから設定する
     */
    public function safeSet(string $option, mixed $value): bool
    {
        // 存在確認
        $doc = tidy_get_opt_doc($this->tidy, $option);
        if ($doc === false) {
            echo "⚠️  オプション '{$option}' は存在しません(スキップ)" . PHP_EOL;
            return false;
        }

        $ok = tidy_setopt($this->tidy, $option, $value);
        printf(
            "  %s %-22s = %-8s // %s%s",
            $ok ? '✅' : '❌',
            $option,
            var_export($value, true),
            mb_substr($doc, 0, 40),
            PHP_EOL
        );
        return $ok;
    }

    public function getTidy(): tidy
    {
        return $this->tidy;
    }
}

$setter = new TidyDocumentedOptSetter('<html><body><p>安全設定テスト</p></body></html>');

$setter->safeSet('indent',       true);
$setter->safeSet('wrap',         80);
$setter->safeSet('tidy-mark',    false);
$setter->safeSet('ghost-option', 'value');  // 存在しないオプション
$setter->safeSet('quiet',        true);

出力例:

  ✅ indent                  = true     // indents each new tag for readability...
  ✅ wrap                    = 80       // sets the column at which line wrapping...
  ✅ tidy-mark               = false    // adds a meta element to the document...
⚠️  オプション 'ghost-option' は存在しません(スキップ)
  ✅ quiet                   = true     // suppress optional warning/info messages

例7: 複数オプションをチェーン設定してレポートするクラス

<?php
class TidyOptChainBuilder
{
    private tidy          $tidy;
    private array         $applied = [];
    private array         $failed  = [];

    public function __construct(private readonly string $html)
    {
        $this->tidy = tidy_parse_string($html, [], 'UTF8');
    }

    public function set(string $option, mixed $value): self
    {
        $ok = tidy_setopt($this->tidy, $option, $value);
        if ($ok) {
            $this->applied[$option] = $value;
        } else {
            $this->failed[$option]  = $value;
        }
        return $this;
    }

    public function build(): string
    {
        $config = tidy_get_config($this->tidy);
        $tidy   = tidy_parse_string($this->html, $config, 'UTF8');
        tidy_clean_repair($tidy);
        return tidy_get_output($tidy);
    }

    public function report(): void
    {
        echo "=== オプション設定レポート ===" . PHP_EOL;
        echo "✅ 適用済み (" . count($this->applied) . " 件):" . PHP_EOL;
        foreach ($this->applied as $opt => $val) {
            printf("   %-22s = %s%s", $opt, var_export($val, true), PHP_EOL);
        }
        if (count($this->failed)) {
            echo "❌ 失敗 (" . count($this->failed) . " 件):" . PHP_EOL;
            foreach ($this->failed as $opt => $val) {
                printf("   %-22s = %s%s", $opt, var_export($val, true), PHP_EOL);
            }
        }
    }
}

$html   = '<HTML><BODY><H1>チェーンテスト</H1><P>本文</BODY>';
$output = (new TidyOptChainBuilder($html))
    ->set('indent',        true)
    ->set('wrap',          80)
    ->set('tidy-mark',     false)
    ->set('quiet',         true)
    ->set('output-xhtml',  false)
    ->set('bad-option',    'x')     // 無効
    ->set('indent-spaces', 4)
    ->build();

// レポートを表示するためにインスタンスを保持して再実行
$builder = new TidyOptChainBuilder($html);
$builder
    ->set('indent',        true)
    ->set('wrap',          80)
    ->set('tidy-mark',     false)
    ->set('quiet',         true)
    ->set('output-xhtml',  false)
    ->set('bad-option',    'x')
    ->set('indent-spaces', 4);

$builder->report();
echo PHP_EOL . "=== 整形結果 ===" . PHP_EOL;
echo $builder->build();

出力例:

=== オプション設定レポート ===
✅ 適用済み (6 件):
   indent                 = true
   wrap                   = 80
   tidy-mark              = false
   quiet                  = true
   output-xhtml           = false
   indent-spaces          = 4
❌ 失敗 (1 件):
   bad-option             = 'x'

=== 整形結果 ===
<!DOCTYPE html>
<html>
<head>
  <title></title>
</head>
<body>
    <h1>チェーンテスト</h1>
    <p>本文</p>
</body>
</html>

7. 関連関数との比較

関数名用途戻り値
tidy_setopt()オプションを1件設定bool
tidy_getopt()オプションの現在値を1件取得mixed
tidy_get_config()全オプションを配列で取得array
tidy_get_opt_doc()オプションの説明文を取得string|false
tidy_reset_config()全オプションをデフォルトにリセットbool
tidy_set_encoding()エンコーディングを専用メソッドで設定bool
tidy_parse_string()解析時に配列でまとめて設定tidy|false

使い分けのポイント: 多数のオプションをまとめて設定するなら tidy_parse_string() の第2引数、特定の1件だけ後から変更するなら tidy_setopt() が適切です。


8. よくある落とし穴と注意点

① tidy_setopt() 後も再解析しないと出力に反映されない

tidy_setopt() はオプション値を変更するだけで、既に解析済みの内部ツリーには影響しません。変更を出力に反映するには tidy_parse_string() を再実行してください。

// NG: setopt だけでは出力は変わらない
$tidy = tidy_parse_string($html, [], 'UTF8');
tidy_setopt($tidy, 'indent', true);
tidy_clean_repair($tidy);
echo tidy_get_output($tidy); // indent は反映されない

// OK: 再解析する
tidy_setopt($tidy, 'indent', true);
$config = tidy_get_config($tidy);          // 変更後の全設定を取得
$tidy   = tidy_parse_string($html, $config, 'UTF8'); // 再解析
tidy_clean_repair($tidy);
echo tidy_get_output($tidy); // indent が反映される

② 無効なオプション名は false が返る

存在しないオプション名や誤ったスペルでは false が返ります。tidy_get_opt_doc() で事前に存在確認するか、戻り値を必ず確認してください。

var_dump(tidy_setopt($tidy, 'no-such-opt', true)); // bool(false)

③ 値の型がオプションと合わない場合も false になる

wrap(int 型)に文字列を渡したり、indent(bool 型)に整数以外を渡すと false が返ることがあります。

tidy_setopt($tidy, 'wrap', 'wide');  // ❌ int 型に string → false
tidy_setopt($tidy, 'wrap', 80);      // ✅ 正しい

④ オプション名は小文字ハイフン区切りが基本

'indentSpaces''IndentSpaces' などキャメルケース・パスカルケースは認識されません。

tidy_setopt($tidy, 'indent-spaces', 4); // ✅ 正しい
tidy_setopt($tidy, 'indentSpaces',  4); // ❌ false が返る

⑤ tidy_get_config() と組み合わせて再解析するのが定番パターン

変更後の設定をまとめて再解析に使う場合は tidy_get_config() で全オプションを配列化し、それを tidy_parse_string() の第2引数に渡すのが最も確実です。

tidy_setopt($tidy, 'indent', true);
tidy_setopt($tidy, 'wrap',   80);
$config = tidy_get_config($tidy);                     // 変更後の全設定を取得
$tidy   = tidy_parse_string($html, $config, 'UTF8'); // 再解析
tidy_clean_repair($tidy);
echo tidy_get_output($tidy);

9. まとめ

項目内容
主な用途tidy オブジェクトのオプションを1件ずつ個別に設定する
戻り値true(成功)/ false(無効名・型不一致)
OOP 版$tidy->setOpt(string $option, mixed $value)
値の型オプションに応じて boolintstring
出力への反映tidy_get_config()tidy_parse_string() の再実行が必要
まとめて設定したい場合tidy_parse_string() の第2引数(配列)を使う
よく使う組み合わせtidy_getopt(), tidy_get_config(), tidy_get_opt_doc(), tidy_reset_config()

tidy_setopt() は Tidy の設定をピンポイントで後から変更するための関数です。tidy_get_config() で変更後の全設定を取得し tidy_parse_string() で再解析するパターンを定番として習得しておくと、柔軟な設定切り替えを安全かつ確実に実装できます。

タイトルとURLをコピーしました