Excessive use of $this as object param in PHP, How to avoid?
I've been working in PHP5 for a couple of years now and have developed a lightweight MVC framework that I use to speed up site development. Works great, automated formbuilder, autoSQL module, etc.
One bad habit that I have developed, however, is relying on $this as an easy object param. I have yet to figure out how to truly encapsulate data without having to extend from a base class (where all site variables are defined) and using a setter method to populate each object instance with the passed $this object. Everything works, but it's ridiculous that each object has to know about the entire application state. I would like each object to perform it's designated task only requiring a minimum knowledge of the "outside" context.
For example, let's say I have a class that generates a customer's开发者_如何学JAVA account details:
// pseudo account
Class account extends siteBase {
protected $formObj;
public $custID = 1;
public $name;
public $email;
// etc...
function __construct() {
$this->formObj = new FormBuild($this); // easy $this passing
$this->formObj->getFormData();
$this->formObj->build();
}
}
// pseudo form builder class
Class FormBuild extends siteBase {
protected $data;
function __construct($caller) {
$this->set($caller);
}
function set($arr) {
foreach($arr as $key => $val) {
$this->$key = $val;
}
}
function getFormData() {
$this->data = new FormQuery($this); // more easy $this passing
}
function build() {
foreach($this->data as $key => $val) {
echo $key . " " . $val . "<br>";
}
}
}
Class FormQuery extends siteBase {
function __construct($caller) {
$this->set($caller);
}
function query() {
$sql = "SELECT email, phone FROM account WHERE custID = '$this->custID'";
// query & return return result, etc.
}
}
What do the "pros" do this in situation? I'd love to clean up the interface a bit...
There are many approaches to this problem. Here are a few
- Global or class constants
- External config/static data (INI style, xml, yaml, database, etc) read by a config class of some sort
- The registry pattern
- The depdency injection/inversion-of-control pattern
They all have their ups and downs - there is no "one true solution."
Try to take the perspective of the client code: a derived class should have the same interface as the parent class but a different implementation.
A messy interface such as methods in parent classes that aren't used in derived classes should never exist and would be a good hint to start refactor. Another strong hint that you most probably noticed is that the methods don't take the same arguments (comparing account::__construct()
to FormBuild::__construct($caller)
, both deriving from siteBase::__construct()
).
I would refactor with configuration in mind, what if siteBase
includes a database but a deriving class needs a different/a set of different databases? Try to draw out your common classes and see which ones that really share signature, pair together a few at a time.
Both responses above are correct.
I have built-in a registry object/properties container that I pass to appropriate objects that no longer need to inherit from an application base class. Bit of a hassle compared to passing $this around, but makes for better planning and forces me to define what my objects need to know vs. knowing everything.
The refactoring advice also got me stripping down a few frequently used objects to only doing their job vs. several jobs at once.
Still a ways to go though, I've gotten used to knowing everything about the application from almost anywhere in the app...
精彩评论