在PHP中,当保存匿名函数的变量名是变量-变量时,如何通过闭包进行递归

问题描述 投票:0回答:1

我有大约 100 篇文章的列表,每篇文章中都有一个条款列表。 这些条款是不同深度级别的列表。

$clauses = array(
  [
    'Fields' => ['Clause' => 'clause 1', 'Status' => 'Draft']
  ],
  [
    'Fields' => ['Clause' => 'clause 2', 'Status' => 'Draft'],
    'SubClauses' => [
      [
        'Fields' => ['Clause' => 'clause 2_a', 'Status' => 'Draft'],
        'SubClauses' => [
          [
            'Fields' => ['Clause' => 'clause 2_a_1', 'Status' => 'Draft']
          ],
          [
            'Fields' => ['Clause' => 'clause 2_a_2', 'Status' => 'Draft']
          ]
        ]
      ]
    ]
  ],
  [
    'Fields' => ['Clause' => 'clause 3', 'Status' => 'Draft']
  ]
);

echo PHP_EOL;

为了从 $clauses 数组创建一个 html 有序列表,我构建了这个:

function htmlList ( $clauses, $depth = 0 ) {
  
  if ( $depth == 0 ) {
    echo '<ol type="1">';
  } elseif ( $depth == 1 ) {
    echo '<ol type="i">';
  } else {
    echo '<ol type="a">';
  }
  
  foreach ( $clauses as $key => $clause ) {
    if ( isset($clauses[$key]['SubClauses']) ) {
      echo '  <li>' . $clauses[$key]['Fields']['Clause'];
      htmlList ( $clauses[$key]['SubClauses'], ++$depth );
    } elseif ( isset($clauses[$key]['Fields']) ) {
      echo '  <li>' . $clauses[$key]['Fields']['Clause'] . '</li>';
    }
  }
  
  $depth--;
  echo '  </li>';
  echo '</ol>';
}

htmlList ( $clauses );

echo PHP_EOL;

它仅构建单篇文章的列表。 当代码循环到下一篇文章时,我收到错误,因为函数已经定义了。

我想将html保留在模板中,而不是将其放在代码文件中,所以我在模板中有可以在那里写入html的功能。

我需要在下一篇文章循环时更改函数的名称,因此我将其转换为闭包并将其分配给变量。 我正在传递该函数,因为我需要它递归。

$htmlList = function ( $clauses, $depth = 0 ) use ( &$htmlList ) {
  
  if ( $depth == 0 ) {
    echo '<ol type="1">';
  } elseif ( $depth == 1 ) {
    echo '<ol type="i">';
  } else {
    echo '<ol type="a">';
  }
  
  foreach ( $clauses as $key => $clause ) {
    if ( isset($clauses[$key]['SubClauses']) ) {
      echo '  <li>' . $clauses[$key]['Fields']['Clause'];
      $htmlList ( $clauses[$key]['SubClauses'], ++$depth );
    } elseif ( isset($clauses[$key]['Fields']) ) {
      echo '  <li>' . $clauses[$key]['Fields']['Clause'] . '</li>';
    }
  }
  
  $depth--;
  echo '  </li>';
  echo '</ol>';
};

$htmlList ( $clauses );

echo PHP_EOL;

这也适用于单篇文章,但允许动态更改名称。 然后,我将保存函数名称的变量的名称设为动态。

$articles = array(
    ['Title' => 'title 1', 'Status' => 'Draft'],
    ['Title' => 'title 2', 'Status' => 'Draft'],
);

for ( $i = 0; $i < sizeof($articles); $i++ ) {
  
  echo $articles[$i]['Title'] . PHP_EOL;
  
  $htmlList = 'htmlList' . '_' . $i;
  $$htmlList = function ( $clauses, $depth = 0 ) use ( &$$htmlList ) {
    
    if ( $depth == 0 ) {
      echo '<ol type="1">';
    } elseif ( $depth == 1 ) {
      echo '<ol type="i">';
    } else {
      echo '<ol type="a">';
    }
    
    foreach ( $clauses as $key => $clause ) {
      if ( isset($clauses[$key]['SubClauses']) ) {
        echo '  <li>' . $clauses[$key]['Fields']['Clause'];
        $$htmlList ( $clauses[$key]['SubClauses'], ++$depth );
      } elseif ( isset($clauses[$key]['Fields']) ) {
        echo '  <li>' . $clauses[$key]['Fields']['Clause'] . '</li>';
      }
    }
    
    $depth--;
    echo '  </li>';
    echo '</ol>';
  };
  
  $$htmlList ( $clauses );
  
}

这就是它破裂的地方。 它不喜欢 use() 中的可变命名函数名,并且在 $$ 处出错,因为它是一个可变变量,它只允许 1 $ 而我有 2 $$,因为变量名的值发生了变化。

是否最好将函数保存在模板外部的主代码中,这样就不必为每篇文章重新构建,或者将函数放在模板中并将 html 保留在主代码文件之外? 围绕 html 的所有其他构造通常都在模板文件中。

如何将循环的每篇文章的子句转换为 html 列表?

php recursion closures anonymous-function variable-variables
1个回答
0
投票

要解决您的问题并为每篇文章生成 HTML 列表而不会遇到函数重新定义错误,您可以在循环外部定义一次递归函数,然后为每篇文章调用它。这种方法将您的 HTML 保留在模板内,并避免多次重新定义函数。

$htmlList = function ($clauses, $depth = 0) use (&$htmlList) {
    if ($depth == 0) {
        echo '<ol type="1">';
    } elseif ($depth == 1) {
        echo '<ol type="i">';
    } else {
        echo '<ol type="a">';
    }

    foreach ($clauses as $clause) {
        echo '<li>' . $clause['Fields']['Clause'];
        if (isset($clause['SubClauses'])) {
            $htmlList($clause['SubClauses'], $depth + 1);
        }
        echo '</li>';
    }

    echo '</ol>';
};

$clauses1 = array(
    [
        'Fields' => ['Clause' => 'clause 1', 'Status' => 'Draft']
    ],
    [
        'Fields' => ['Clause' => 'clause 2', 'Status' => 'Draft'],
        'SubClauses' => [
            [
                'Fields' => ['Clause' => 'clause 2_a', 'Status' => 'Draft'],
                'SubClauses' => [
                    [
                        'Fields' => ['Clause' => 'clause 2_a_1', 'Status' => 'Draft']
                    ],
                    [
                        'Fields' => ['Clause' => 'clause 2_a_2', 'Status' => 'Draft']
                    ]
                ]
            ]
        ]
    ],
    [
        'Fields' => ['Clause' => 'clause 3', 'Status' => 'Draft']
    ]
);

$clauses2 = array(
);

$articles = array(
    [
        'Title' => 'Article 1',
        'Status' => 'Draft',
        'Clauses' => $clauses1
    ],
    [
        'Title' => 'Article 2',
        'Status' => 'Draft',
        'Clauses' => $clauses2
    ],
);

foreach ($articles as $article) {
    echo '<h2>' . $article['Title'] . '</h2>';
    if (isset($article['Clauses'])) {
        $htmlList($article['Clauses']);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.