我正在尝试创建一个面向对象的表单生成器。请记住,它只会被我们公司的少数人用来解决特定的问题。
我目前面临两个小问题。
创建元素的语法
我能采取的方法很少。
正在构造函数中设置所有内容。作为一个缺点,这可能导致不一致的构造函数使用
Input::create('text', 'name', array('maxlength' => 10));
将构造函数限制为键入并仅将最常用的属性作为方法公开(保留一个方法用于大规模属性设置)
Input::create('text')->name('name')->value('value')->attribute('max_length', 10);
通过为每个属性创建一个方法或使用__call
魔术方法将每个属性公开为方法,这将导致IDE中不支持自动完成。即使现在,我也可以保留attribute
方法。
Input::create()->type('text')->name('name')->value('value')->max_length(10)->id('id'); //etc.
目前,我认为第二种方法是最好的,因为它从两个世界都保留了"好"的东西。As仍然提供了一种对一些工作进行抽象的方法,因为例如方法required
不仅会设置所需的属性,还会根据需要为验证对象标记该字段。
方法2和方法3的代码重复
由于存在每个元素都可以使用的属性,但也存在仅可由3或4个元素使用的属性(例如HTML5属性form
)。
每个元素都可以从基本元素继承,基本元素具有针对每个元素通用的属性的方法(例如name
)。部分可用的属性可以通过接口解决,但这会导致代码重复,因为它们不能包含方法体。
特性将是解决方案,但遗憾的是,我被困在PHP 5.3上,无法升级。这让我要么实现Mixin,要么实现Composition模式,这可能再次导致不支持自动完成。当使用第二种方法时,这将得到部分缓解。
所以我的实际问题是:
哪种方法最合适?(适用于最小的代码重复、可靠的代码重用和易于实现)
我意识到这很可能会产生基于观点的答案,所以如果真的发生了,我提前道歉。
我意识到这是一个老问题,但评论中有人提到了我创建的一个名为htmlgen的项目,该项目反映在packagist上。我最近发布了一个新的2.x版本,它使PHP中的HTML生成变得非常愉快,我在这里加入了一些支持。
use function htmlgen'html as h;
echo h('input', ['name'=>'catQty', 'value'=>500])
将呈现
<input name="catQty" value="500">
然而,就潜在的而言,这个例子几乎没有触及表面
h('#wrapper',
h('h1.title', 'Hello, World'),
h('p',
h('comment', 'link to duckduckgo'),
h('a', ['href'=>'https://duckduckgo'], 'search the internet')
)
);
这是输出(实际输出没有空白)
<div id="wrapper">
<h1 class="title">Hello, World</h1>
<p>
<!-- link to duckduckgo -->
<a href="https://duckduckgo">search the internet</a>
</p>
</div>
它在呈现数据集合时也非常方便
use function htmlgen'html as h;
use function htmlgen'map;
$links = [
'home' => '/',
'cats' => '/cats',
'milk' => '/milk',
'honey' => '/honey',
'donuts' => '/donuts',
'bees' => '/bees'
];
echo h('nav',
h('ul',
map($links, function($href, $text) { return
h('li',
h('a', ['href'=>$href], $text)
);
})
)
);
将输出(同样,空白仅用于显示)
<nav>
<ul>
<li><a href="/">home</a></li>
<li><a href="/cats">cats</a></li>
<li><a href="/milk">milk</a></li>
<li><a href="/honey">honey</a></li>
<li><a href="/donuts">donuts</a></li>
<li><a href="/bees">bees</a></li>
</ul>
</nav>
这都是100%的PHP,没有自定义的、专有的有趣的业务。它表现力很强,适合于伟大的作品。您可以将模板分解为易于重用的函数或require
调用。
IMO我会选择第二个选项。可能是因为它让我想起了jQuery。
Input::create('text')->name('name')->value('value')->attribute('max_length', 10);
在接口类"FormElements"中定义更通用的字段,如"name"、"value"、"attribute",并在类"Input"、"Select"等中实现/扩展。
尽管我个人更喜欢第二种选择。。用外星人保罗的话说:"有时候你只需要掷骰子"。