框架接口;有限的还是广泛的、甜蜜的方法同义词?

发布于 2024-11-16 15:21:52 字数 2955 浏览 1 评论 0原文

我正在开发一个 PHP 框架;它一开始是针对特定应用程序的,但是它已经转变为一个更加不可知的 HMVC 风格的平台,我打算将其重新用于进一步的项目。

无论如何,虽然我是该项目的唯一开发人员,但我对开发核心界面的选择有点矛盾。

我的主要问题是(并且我知道这可能被认为有点主观)是创建一个严格的接口来让客户端程序员工作更合适,还是允许更多的灵活性。通过一个示例可以最好地描述这一点:

class MyDataClass{
    public function getData($key){}
    public function setData($key, $value){}
}

这满足了简单数据注册表的要求(除了实现细节)。这些方法可以通过返回 $this 进行链接,并且可以包含必要的验证逻辑。现在是另一种 PHP 方法:

class MyDataClass{
    public function __get($key){}
    public function __set($key, $value){}
}

当然,这也可行,并且通过使用 PHP 的魔力提供了干净的实现。现在,我似乎最常采用的方法是:

class MyDataClass{
    public function getData($key){}
    public function setData($key, $value){}
    public function __get($key){ return $this->getData($key); }
    public function __set($key){ $this->setData($key); }
}

提供多个入口点是否像此示例所示是一个糟糕的设计选择?我一直认为将所有交互逻辑集中到一个方法中,但允许不同的语法选择,这将是一个好主意。我现在正在重新考虑这一点,赞成采用更严格的切入点。一个不太简单的例子:

class MySuperDataClass implements ArrayAccess{

    // these do the work
    public function getData($key){}
    public function setData($key, $value){}
    public function getChild($name){}
    public function setChild($name, self $child){}

    // these are just sugary synonyms
    public function offsetGet($key){}
    public function offsetSet($key, $value){}
    public function __get($name){}
    public function __set($name, self $child){}

    // ...

}

想法?


OZ_的回应之后,我意识到我没有证明我的选择是合理的,也没有理解我的方法的意图。

例如,直接方法调用(例如getData())将在控制器中使用,以将数据绑定到视图。

$view->setData('foo', 'bar')
     ->setData('alpha', 'beta')
     ->setData('hello', 'world');

而在视图生成中使用 Magic Sugar 是为了提高可读性和简洁性。

<p><?php echo $view['foo']; ?></p>
<p><?php echo $view['alpha']; ?></p>
<p><?php echo $view['hello']; ?></p>

这就是我参加这样一个大会的原因。我仍然认为这是一个很好的方法,但正如这个问题所暗示的那样,我现在持观望态度,支持更好的做法。


另外:性能正在成为一个问题,因为我看到应用程序不断增长,并且这些调用正在迭代地进行,通过使用我将调用堆栈加倍的糖。当然,我知道微优化,但我认为瓶颈潜力会增加,尤其是在处理 PHP 魔法时(如果我被引导正确理解,尤其是 __call()) 唯一的检查方法是分析,当然;我一直是一个不成熟的优化者,我想改掉这个习惯。打破不良的设计习惯也很重要。


@jgauffin; View 类为此行为实现了 ArrayAccess、Iterator 和 Countable,并使用了 __get/<代码>__set 魔法。这是视图的糖,而调用原始方法来绑定来自控制器的数据。

<?php if($view->canRender('post')): ?>
<div>
<?php foreach($view->post as $post): ?>
    <p><?php echo $post['text']; ?></p>
    <?php if($post->canRender('comments')): ?>
    <div>
    <?php foreach($post->comments as $comment): ?>
        <p><?php echo $comment['text']; ?>
    <?php endforeach; ?>
    </div>
    <?php endif; ?>
<?php endforeach; ?>
</div>
<?php endif; ?>

I'm developing a PHP framework; it started off as application-specific, however it has moved into a more agnostic HMVC-style platform which I intend on re-purposing for further projects.

Anyways, while I'm the only developer on the project as it stands, I'm a bit conflicted on my choices of developing the core interfaces.

My main question is (and I understand this could be deemed slightly subjective) is it more appropriate to create a strict interface through which client programmers will work, or permit a bit more flexibility. This is best described through an example:

class MyDataClass{
    public function getData($key){}
    public function setData($key, $value){}
}

This satisfies the requirements (save for implementation details) of a simple data registry. The methods are chain-able by returning $this, and can contain necessary validation logic. Now the alternative PHP approach:

class MyDataClass{
    public function __get($key){}
    public function __set($key, $value){}
}

Sure that works too, and provides a clean implementation through the use of PHP's magic. Now, the approach I've seemed to take most often is:

class MyDataClass{
    public function getData($key){}
    public function setData($key, $value){}
    public function __get($key){ return $this->getData($key); }
    public function __set($key){ $this->setData($key); }
}

Is providing multiple entry points as this example shows a poor choice in design? I always figured it would be a good idea, by centralizing any interaction logic to a single method, but permitting different syntactic choices. I'm now reconsidering this, in favor of a much stricter entry point. A less brief example:

class MySuperDataClass implements ArrayAccess{

    // these do the work
    public function getData($key){}
    public function setData($key, $value){}
    public function getChild($name){}
    public function setChild($name, self $child){}

    // these are just sugary synonyms
    public function offsetGet($key){}
    public function offsetSet($key, $value){}
    public function __get($name){}
    public function __set($name, self $child){}

    // ...

}

Thoughts?


I realized after OZ_'s response that I hadn't justified my choice, for understanding the intent of my approach.

For instance, direct method calls (getData() for example) would be used in controllers, to bind data to a view.

$view->setData('foo', 'bar')
     ->setData('alpha', 'beta')
     ->setData('hello', 'world');

Whereas magic sugar is used in view generation for readability and brevity.

<p><?php echo $view['foo']; ?></p>
<p><?php echo $view['alpha']; ?></p>
<p><?php echo $view['hello']; ?></p>

This is how I came to such a convention. I still think it's a nice approach, but as this question alludes, I'm on the fence now in favor of better practices.


Also: Performance is becoming a concern, as I see the application growing, and these calls are being made iteratively, by using the sugar I'm doubling up my call stack. Sure, micro-optimization I know, but I would think bottleneck potential increases, especially when dealing with PHP magic (if I've been led to understand correctly, especially __call()) The only way to check is to profile, sure; I've always been a premature optimizer, a habit I'd like to break. Breaking poor design habits is important too.


@jgauffin; the View classes implement ArrayAccess, Iterator and Countable for this behavior, as well as making use of __get/__set magic. This is the sugar for the view, whereas the raw methods are called to bind data from the controllers.

<?php if($view->canRender('post')): ?>
<div>
<?php foreach($view->post as $post): ?>
    <p><?php echo $post['text']; ?></p>
    <?php if($post->canRender('comments')): ?>
    <div>
    <?php foreach($post->comments as $comment): ?>
        <p><?php echo $comment['text']; ?>
    <?php endforeach; ?>
    </div>
    <?php endif; ?>
<?php endforeach; ?>
</div>
<?php endif; ?>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

新雨望断虹 2024-11-23 15:21:52

想法:

  1. 虽然至少存在一种方法,您可以在没有魔术方法的情况下构建类 - 使用这种方式,如果可以的话避免魔术方法。
  2. 如果你不能在接口中描述类 - 类的设计是错误的。
  3. 注册表是不好的模式。如果您需要注册表 - 您的设计有问题。

关于模式和设计的好书

Thoughts:

  1. While exists at least 1 way, where you can build class without magic methods - use that way, avoid magic methods if you can.
  2. If you can't describe class in interface - class was designed wrong.
  3. Registry is bad pattern. If you need registry - something is wrong in your design.

Good book about patterns and design

灼痛 2024-11-23 15:21:52

我认为你前进的方向很棒。该接口将具有 setData/getData 方法。您的实现将实现这些方法,为了方便起见,您可以实现 __set / __get 来调用接口方法。

如果另一个程序员想要扩展功能或向您的系统添加插件,他需要确保他的类实现了您的 setData/getData 方法。

I think the direction you are going is great. The interface would have the methods setData/getData. Your implementation would implement those methods and for convenience you could implement __set / __get to call the interface methods.

IF another programmer wanted to extend the functionality or add a plugin to your system he would need to make sure his classes implemented your setData/getData method.

恋竹姑娘 2024-11-23 15:21:52

您想通过数据类实现什么目标?

我看不出以下之间的区别:

yourClass.Set("someNAme", "someValue");

someArray["someName"] = "someValue";

What are you trying to achieve with your data class?

I don't see the difference between:

yourClass.Set("someNAme", "someValue");

and

someArray["someName"] = "someValue";
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文