use of pseudostatic methods on the example of Zend_Db_ActiveRecord
It so happened that while mastering the Zend Framework, I decided to write the Zend_ActiveRecord component in terms of functionality as similar to Rails as possible. A similar proposal arose on the zenda community, but has not been updated for a long time, and it required php 5.3 because of its __callStatic (). This fact did not suit me, but the need to call dynamic methods of the model class as static still remains a very relevant topic, but I tried to figure it out just by the example of my own ActiveRecord for the zend.
Let's say we have a Post model that represents a table (or a service ) blog entries.
It would be logical and convenient to search as
Thus, we get rid of the need to instantiate the model every time we need access to search methods. At first glance, it seems enough to describe this method as static, but! When the static method is called, the constructor is not called, and it is in it that the main functions should be implemented by logic to bring the model to working condition. For example, one of the main advantages of the ActiveRecord pattern is the integrity and flexible use of dependent models, i.e. associations, so let's try to add, for example, comments to posts and search for all posts AND related comments. In Rails, it would look like this:
has_many and belongs_to in Rails are methods for registering associations, similar to php it should look like this:
The first thing that catches your eye is that we must use static methods to declare associations. This is necessary because at the stage of invoking static find we do not have an instance of the class, and the initializer must be called manually from find () and not from the default constructor, which is inconvenient, especially if you use other functions in the initialization body that By default they imply an instance of the class. for instance
With a static call, this will cause a fatal error.
There are also situations when you need to call find from an already created instance of a class
All this leads to the fact that at different points in the life cycle of the model it is necessary to know how the method was called, either static or otherwise. The solution was found: to imply the find method as NOT STATIC by default, which will not prevent us from invoking it statically, but with a static call, create a temporary instance of the class. PHP itself suggested a convenient one-line method.
or you can use the strapping
With such a call, we simply emulate in the pseudostatic method itself actions that would be inconvenient to use in the rest of the code. Those. in this case, the call
and
absolutely identical, but in the latter case, we do not need to create an instance of the class each time
Let's say we have a Post model that represents a table (or a service ) blog entries.
class Post extends Zend_ActiveRecord_Abstract {}
It would be logical and convenient to search as
Post :: find ('all');
Thus, we get rid of the need to instantiate the model every time we need access to search methods. At first glance, it seems enough to describe this method as static, but! When the static method is called, the constructor is not called, and it is in it that the main functions should be implemented by logic to bring the model to working condition. For example, one of the main advantages of the ActiveRecord pattern is the integrity and flexible use of dependent models, i.e. associations, so let's try to add, for example, comments to posts and search for all posts AND related comments. In Rails, it would look like this:
class Post <ActiveRecord :: Base
has_many: comments
end
class Comment <ActiveRecord :: Base
belongs_to: post
end
Post.find: all,: include =>: comments
has_many and belongs_to in Rails are methods for registering associations, similar to php it should look like this:
class Post extends Zend_ActiveRecord_Abstract {
// allocate a separate function for initialization, because in php
// there is no default constructor for static calls
protected static function initialize () {
// comments - in the plural, as in Rails,
// this parameter is processed by the inflector, so do not be confused
self :: has_many ('comments');
}
}
class Comment extends Zend_ActiveRecord_Abstract {
protected static function initialize () {
self :: belongs_to ('post');
}
}
// search
Post :: find (array ('all', 'include' => 'comments'));
The first thing that catches your eye is that we must use static methods to declare associations. This is necessary because at the stage of invoking static find we do not have an instance of the class, and the initializer must be called manually from find () and not from the default constructor, which is inconvenient, especially if you use other functions in the initialization body that By default they imply an instance of the class. for instance
class Post extends Zend_ActiveRecord_Abstract {
function initialize {
self :: has_many ('comments');
// for example, set the initialization date of the object
$ this-> set_attribute ('initialized_at', timestamp ());
}
}
With a static call, this will cause a fatal error.
There are also situations when you need to call find from an already created instance of a class
// post feed with id = 1
$ post = new Post (1);
// call the search for something
$ something = $ post-> find (array ('all', 'conditions' => array (......));
// or upload comments to the post, the find method of the model is called Comment, already created by default
$ otherthing = $ post-> comments-> find (array ('all'));
All this leads to the fact that at different points in the life cycle of the model it is necessary to know how the method was called, either static or otherwise. The solution was found: to imply the find method as NOT STATIC by default, which will not prevent us from invoking it statically, but with a static call, create a temporary instance of the class. PHP itself suggested a convenient one-line method.
class Zend_ActiveRecord_Abstract {
public function find ($ options = array ()) {
// determine the type of call by the presence of $ this. In a static context, a variable is not defined
if (! Isset ($ this)) $ This = new self (); else $ This = $ this; // $ this and $ This are different variables
// further we work with the object without thinking about the consequences, but using $ This instead of $ this
$ This-> mehod ();
...
}
}
or you can use the strapping
class Zend_ActiveRecord_Abstract {
public static funtion get_instance () {
$ obj = new self ();
return $ obj;
}
public funtion find ($ options = array ()) {
if (! isset ($ this)) return self :: get_instance () -> find ($ options);
// further work as usual
}
}
With such a call, we simply emulate in the pseudostatic method itself actions that would be inconvenient to use in the rest of the code. Those. in this case, the call
$ post_instance = new Post ();
$ post_instance-> find ();
and
Post :: find ();
absolutely identical, but in the latter case, we do not need to create an instance of the class each time