PHP 中的延迟加载类方法

发布于 2024-11-16 20:32:44 字数 543 浏览 0 评论 0原文

我有一堂课,里面有一些相当大的方法。在它的基本和最常见的状态下,大多数功能并不是必需的,所以我想知道是否有一种方法可以延迟加载类的一部分。这些方法需要能够访问私有/受保护的成员,因此如果这些方法是类的本机方法,那将是理想的选择,但是在寻找其他解决方案时,我遇到了 this 讨论了在回调中使用私有成员,这将是一个可行的解决方案(我会使用包含调用函数的单独类回调和懒惰加载该类)。那是 2009 年,我不知道这个功能是否在 PHP 的更高版本中被删除,但它似乎不适用于 5.3.5

有没有办法做到这一点,或者你有什么建议对于我应该关注的其他模式?

谢谢。


哇!感谢所有的答案。我认为你们中的一些人认为这可能是一个过早的优化,或者更糟糕的是,根本不是一个优化,这是非常有效的,我将进行分析,以检查我选择的任何解决方案实际上是否有帮助而不是造成伤害。 ... 现在正确地阅读并消化你所有的想法。再次感谢。

I have a class with a few rather large methods. In it's basic and most common state most of the functionality is not required though, so I was wondering if there is a way of lazy loading just parts of the class. The methods need to be able to access private/protected members so it would be ideal if the methods were native to the class, however in looking for other solutions I came across this which discusses using private members in callbacks which would be a workable solution (I'd use separate classes that contain a function that calls the callback and lazy load that class). That was 2009 though and whether this functionality has been removed in later versions of PHP i don't know, but it doesn't seem to be working here with 5.3.5

Is there a way of doing this, or do you have any suggestions for other patterns I should be looking at?

Thanks.


Wow! Thanks for all the answers. I think the point a number of you make regarding this being a probable premature optimization, or worse, not an optimization at all is very valid and I will be doing profiling to check that any solution I settle on is actually helping not hurting.
...
Now to read and digest all your thoughts properly. Thanks again.

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

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

发布评论

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

评论(8

风和你 2024-11-23 20:32:44

从 PHP 5.4 开始,您可以(重新)绑定匿名函数和闭包

<?php

class Foo
{
    private $bar = 1;
}

$getBar = function() { return $this->bar; };

$foo = new Foo;
$foo->getBar = $getBar->bindTo($foo, $foo);

echo call_user_func($foo->getBar); // prints "1"

请参阅https://wiki.php.net/rfc/closures/object-extension进行讨论闭包的实现和潜在的问题。

一般来说,如果您发现您的类有许多长方法,请尝试将它们分解为较小的块。用简单的英语描述这些方法的作用。对于每个“和”,创建一个新方法并将代码移到那里。

还要看看该类中的各种属性。如果其中一些在概念上是一致的,请考虑将它们制作成自己的对象。将访问这些属性的任何方法移至新对象以实现内聚。

我还有些质疑您想要将方法“延迟加载”到类中的动机。即使您不使用它们,将它们放在那里也不会出现性能问题。如果这是为了性能优化,那么您可能从错误的角度进行了处理。

另一种选择是使用 Traits,或者更简单,组合

As of PHP 5.4 you can (re-)bind Anonymous Functions and Closures:

<?php

class Foo
{
    private $bar = 1;
}

$getBar = function() { return $this->bar; };

$foo = new Foo;
$foo->getBar = $getBar->bindTo($foo, $foo);

echo call_user_func($foo->getBar); // prints "1"

See https://wiki.php.net/rfc/closures/object-extension for a discussion of the Closure implementation and potential gotchas.

In general, if you find your class has many long methods, try to break them down into smaller chunks. Describe what the methods do in plain english. For every "and" make a new method and move the code there.

Also have a look at the various properties in that class. If some of them go conceptually together, consider making them into an object of their own. Move any methods accessing those properties to the new object for cohesion.

I also somewhat question your motives for wanting to "lazy load" methods into the class. There is no performance complication for having them there, even when you dont use them. If this is for a performance optimization, you are probably approaching it from the wrong end.

Another option would be to use Traits or, even simpler, Composition.

隔纱相望 2024-11-23 20:32:44

回调解决方案看起来非常难看。
您可以使用组合模式和自动加载:

class MyClass
{

protected $logger;

function SomeFunction($arg)
{
    $this->Logger()->write($arg);
}

function Logger()
{
    if (empty($this->logger)) $this->Logger = new Logger(); //lazy initialization of method
    return $this->logger;
}

}

但是,我不得不说,所有这些都只是微观优化,不要浪费您的时间。创建新对象和自动加载另一个文件(使用磁盘)的时间将比使用“大”方法简单初始化对象的时间更长。

Callback solutions looks very ugly.
You can use Composition pattern and autoloading:

class MyClass
{

protected $logger;

function SomeFunction($arg)
{
    $this->Logger()->write($arg);
}

function Logger()
{
    if (empty($this->logger)) $this->Logger = new Logger(); //lazy initialization of method
    return $this->logger;
}

}

But, I have to say, that all of it is just micro-optimizations, don't waste your time. Time of creating new object and autoloading another file (it's using disk), will be bigger, than simple initialization of the object with "large" methods.

夜声 2024-11-23 20:32:44

我不知道有一种(性能有效的)方法来仅加载类的一部分。

我认为您需要将类的方法分成子类,并使用 自动加载< /a> 加载它们。

完成此操作后,您可以考虑执行以下操作:

class myMainClass
 {

   function bigFatMethod($argument, $argument2)
    {
      return mySubClass::bigFatMethod($this, $argument, $argument2); 
      // (pass $this if necessary)
    }
 }  

这将使 bigFatMethod()myMainClass 内部可调用,但在内部,因为您正在使用自动加载,仅当实际调用 bigFatMethod() 时才会加载必要的代码。

显然,您需要重写 bigFatMethod() 以便可以静态调用它,并且您必须使其访问第一个传递的对象,而不是访问 $this参数(您在父类中将 $this 传递给该参数)。

我自己从来没有这样做过 - 我倾向于将类分成子类,并分别处理它们 - 但我看不出以这种方式做事有任何巨大缺点。

如果您愿意,您甚至可以使用 __call() 魔术方法,它将查找它必须加载的子类,执行该方法并返回结果。

I'm not aware of a (performance effective) way to load only parts of a class.

I think you will need to separate the class's methods into sub-classes, and use autoloading to load them.

Once you have done that, you could think about doing something like this:

class myMainClass
 {

   function bigFatMethod($argument, $argument2)
    {
      return mySubClass::bigFatMethod($this, $argument, $argument2); 
      // (pass $this if necessary)
    }
 }  

This would keep bigFatMethod() callable inside myMainClass, but internally, because you are using autoloading, the necessary code gets loaded only when bigFatMethod() is actually called.

Obviously, you would need to rewrite bigFatMethod() so it can be called statically and instead of accessing $this, you would have to make it access the object passed in its first parameter (to which you pass $this in the parent class).

I have never done this myself - I would tend to split the class into sub-classes, and address them separately - but I can't see any huge downside to doing things this way.

If you wanted, you could even abstract bigFatMethod() using a __call() magic method, which would look up which subclass it has to load, executes the method, and returns the result.

怪我闹别瞎闹 2024-11-23 20:32:44

你的班级可能试图做太多事情。我建议尝试将其分成单独的服务。然后,您可以使用依赖项注入容器(例如 Pimple)仅延迟加载那些实际使用的服务。

我建议不要滥用继承权。相反,您应该优先考虑组合而不是继承。这使您的设计更清晰,代码库更易于维护。

Your class is probably trying to do too much. I would suggest trying to separate it into separate services. You could then use a Dependency Injection Container (eg. Pimple) to lazily load only those services that are actually used.

I'd advise against abusing inheritance. Instead you should favor composition over inheritance. This makes your design cleaner and your code base more maintainable.

Spring初心 2024-11-23 20:32:44
<?php
class BigClass
{
  public function lazy()
  {
    return include 'lazy.func.php';
  }
}

这应该有效并满足您的要求。我还没有真正考虑过它可能产生的任何副作用。

<?php
class BigClass
{
  public function lazy()
  {
    return include 'lazy.func.php';
  }
}

That should work and satisfy your requirements. I haven't really thought much about any side effects it may have.

‖放下 2024-11-23 20:32:44

仅加载类的一部分 - 这是根本不可能的。当您创建类的新实例时,它会初始化整个类,因此不会延迟加载您只需要的函数

to load just part of class - it's simply impossible. When you do make new instance of class, it does initialize whole class and therefore there isn't lazy loading of function you only need

月光色 2024-11-23 20:32:44

您可以编写一个包含所有基本功能的基类,然后使用继承来逐步添加更多专门的功能,并且仅在需要时使用继承类。

PHP 对象继承

You could write a base class which encompasses all the basic functionality, and then use inheritance to incrementally add more specialized features, and only use the inheriting classes where needed.

PHP Object Inheritance.

冷清清 2024-11-23 20:32:44

您可以使用魔术类方法 __get 动态加载属性,或使用魔术方法 __call 委托给其他类/方法。当您仅在访问属性或方法等时才需要初始化它们时,这些非常棒。

奇怪的是,我最近在博客中谈到了这件事,因为我在我的一个项目的一个大课程中需要它。这有点复杂,但我试图简单地解释一下。它可能会给你一些提示。

http://www.kalekold.net/index.php?post=16

http://php.net/manual/en/language.oop5.magic.php

You can use the magic class method __get to load properties dynamically or the magic method __call for delegating to other classes/methods. These are awesome for when you need to initialise properties or methods, etc. only when they are accessed.

Strangely enough i've recently blogged about this very thing because i needed it in a huge class in one of my projects. It's a little involved but i've tried to explain it simply. It may give you a few pointers.

http://www.kalekold.net/index.php?post=16

http://php.net/manual/en/language.oop5.magic.php

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