It so happened that mastering the Zend Framework, I decided to write a Zend_ActiveRecord component in functionality as similar as possible to Rails. A similar
proposal arose in the zend community, but has not been updated for a long time, and at the same time it required php 5.3 because of its __callStatic (). This fact did not suit me, but the need to call the dynamic methods of the class of the model as static still remains a very topical subject, but I tried to deal with this with the example of my own ActiveRecord for zend
Suppose we have a Post model that represents a table (or service) of 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 that it is enough to describe this method as static, but! When a static method is called, the constructor is not called, and it is in it that, logically, the main functions must be implemented to bring the model into a working state. For example, one of the main advantages of the ActiveRecord pattern is the integrity and flexible use of dependent models, ie associations, so we will 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, by analogy with php it should look like this:
class Post extends Zend_ActiveRecord_Abstract {
// select a separate function for initialization, since in php
// 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 need to use static methods to declare associations. This should be done because at the static find stage we do not have an instance of the class, and the initializer call should be done manually from find () and not from the default constructor, which is inconvenient, especially if you use other functions in the initialization body defaults imply an instance of the class. for example
class Post extends Zend_ActiveRecord_Abstract {
function initialize {
self :: has_many ('comments');
// for example, set the object's initialization date
$ this-> set_attribute ('initialized_at', timestamp ());
}
}
With a static call, this will cause fatal error.
There are also situations when you need to call find from an already created class instance.
// loading the post with id = 1
$ post = new Post (1);
// call search for something
$ something = $ post-> find (array ('all', 'conditions' => array (......));
// or loading comments to the post, the find method of the Comment model is 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 a model, it is necessary to know how the method was called, as static or otherwise. The solution was found: to imply the find method as NOT STATIC by default, which does not prevent us from calling it statically, and using a static call to create a temporary instance of the class. PHP itself prompted a convenient way in one line.
class Zend_ActiveRecord_Abstract {
public function find ($ options = array ()) {
// determine the type of call by the presence of $ this. In a static context, the variable is not defined.
if (! isset ($ this)) $ This = new self (); else $ This = $ this; // $ this and $ This are different variables.
// then we work with the object without thinking about the consequences, but using $ This instead of $ this
$ This-> mehod ();
...
}
}
or you can use 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 of action itself, which would be inconvenient to use in the rest of the code. Those. in this case the challenge
$ 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 every time