What is the SPL
SPL (Standard PHP Library) standard PHP library i.e., PHP 5 is on the object-oriented ability to enhance true portrayal, which consists of a series of built-in classes, interfaces and functions. SPL by the addition of the collection, the iterator, new exception type, file and data processing etc. to enhance the productivity of the PHP language. It also provides some very useful features, such as built-Observer design pattern this article to introduce.
This article describes how to use the SPL provided SplSubject
and SplObserver
interfaces as well as SplObjectStorage
classes, quickly realize Observer design pattern.
SplSubject and SplObserver Interface
Observer design pattern defines the dependencies among the many objects of one kind, when the object is viewed is changed, all depending objects are notified and updated automatically, but also between the observer and the objects observed They are loosely coupled. In this mode, there is a target (Subject) and the observer (Observer) two roles. Target character is observed object, hold and control certain state, any number of viewers may be viewed as a target, using the SPL SplSubject
interface specification of the behavior character:
Interface Method SplSubject
Method Statement | description |
---|---|
abstract public void attach ( SplObserver $observer ) |
Add (register) an observer |
abstract public void detach ( SplObserver $observer ) |
Delete an observer |
abstract public void notify ( void ) |
When the state changes, notify all observers |
Observer role is when the target changes need to be informed of the object. SPL with SplObserver
interface specification behavior that role:
SplObserver Methods
Method Statement | description |
---|---|
abstract public void update ( SplSubject $subject ) |
Receive notifications sent by the target when the target is changed; when the target call its attention notify() is called |
The core idea of this design pattern is SplSubject
called when the object will change its state notify()
method, this method is called once, by any previous attach()
method of registering up SplObserver
the object will be to call its update()
updated ways and means.
Why SplObjectStorage class
SplObjectStorage
Class implements the set (as the object is ignored if the key data corresponding to) such a data structure mapping an object-key (Map) or object. Examples of this class like an array, but the object to which it is stored is unique. This feature will contribute a lot of power to quickly implement Observer design pattern, because we do not want to be registered multiple times with an observer. Another feature of this class is directly removed from the specified object, without the need to traverse or search the entire collection.
SplObjectStorage
Examples of the class have been able to store only unique object, because of its SplObjectStorage::attach()
implementation in a first determines whether the specified object has been stored:
Listing 1. SplObjectStorage :: attach () method of some source code
function attach($obj, $inf = NULL)
{
if (is_object($obj) && !$this->contains($obj))
{
$this->storage[] = array($obj, $inf);
}
}
Analog Case
Let us demonstrate the power of the SPL on the Observer design pattern through a simulation case. This case simulates a website user management module, which includes three main functions:
- Add a user
- To specify the user's password is changed to His appointed a new password
- Reset their password when a user forgets a password
Every time after the completion of these functions, you need the password to the user. In addition to traditional sending Email this means to the user, we also need to send an SMS to the user's mobile phone, allowing them to more easily know what the password yes. Suppose our website there is information systems within a station, we call small piece of paper, after the user to change or reset the password, send a small note to them will make them happy.
After analysis, the case for using the Observer design pattern to solve, because the password to change the user's password to the user a variety of means - whether from scratch, users take the initiative to change or reset the system - as a foreign Relationship.
We decided to define a User class represents a user needs to achieve the three functions. This class is the Observer design pattern target (Subject) role. We also need a set of classes that implement functions using various means to send a new password to the user, these class acts as the Observer design mode observer (Observer) role.
After a simple analysis, we draw the UML class diagram:
UML class diagram simulation case
The UML class diagrams, first, the definition of a class named User user simulation case. Although the actual site users have more properties, in particular usually you need ID to identify each user, but we have to highlight the theme of this article, leaving only the required property cases.
Listing 2. User class source code
<?php
class User implements SplSubject {
private $email;
private $username;
private $mobile;
private $password;
/**
* @var SplObjectStorage
*/
private $observers = NULL;
public function __construct($email, $username, $mobile, $password) {
$this->email = $email;
$this->username = $username;
$this->mobile = $mobile;
$this->password = $password;
$this->observers = new SplObjectStorage();
}
public function attach(SplObserver $observer) {
$this->observers->attach($observer);
}
public function detach(SplObserver $observer) {
$this->observers->detach($observer);
}
public function notify() {
$userInfo = array(
'username' => $this->username,
'password' => $this->password,
'email' => $this->email,
'mobile' => $this->mobile,
);
foreach ($this->observers as $observer) {
$observer->update($this, $userInfo);
}
}
public function create() {
echo __METHOD__, PHP_EOL;
$this->notify();
}
public function changePassword($newPassword) {
echo __METHOD__, PHP_EOL;
$this->password = $newPassword;
$this->notify();
}
public function resetPassword() {
echo __METHOD__, PHP_EOL;
$this->password = mt_rand(100000, 999999);
$this->notify();
}
}
User class in order to act as a target role, we need to implement SplSubject
an interface, and in accordance with the law to achieve interface attach()
, detach()
and notify()
it must be implemented. Please note that due to the SplSubject
interface, attach
() 和
detach
() 的参数都使用了类型提示(
of the type hinting ),在实现这两个方法时,也
**不能**
省略参数前面的类型。
we also used the $
observers
example of a property holds SplObjectStorage
an object, used to store up all the registered observers.
Indeed, an array will solve the problem, but will soon be discovered, use the SplObjectStorage
delete an observer how easy it is to implement directly entrusted to the following SplObjectStorage
objects! Yes, most do not need to use the original for
sentence or in an array to traverse the observer array_search
function, to get a line.
Next to act as an observer role in the three categories were defined to send information. For simplicity, we just pretend to send information through text output. You can even pretend that still need to know the user's information. You can look at SplObserver
the interface update
()
method signature, how frustrating it can not accept the target character by calling its notify
parameters given time () method to send notifications. If you try to rewrite update
()
plus second parameter method, you will get a similar
Fatal error: Declaration of EmailSender :: update () must be compatible with that of SplObserver :: update () is the error code execution terminates.
In fact, when the target held by the state (in this case, is the user's password) is updated, how to notify the viewer in two ways. "Pull" method and the "push" approach. SPL using the "pull" method, the viewer need to refer to the destination (as a update()
method of parameter passing) to access its properties. "Pull" approach needs to let the viewer know more about what goals have attributes, which increases their degree of coupling. And also the theme of the observer door wide open, contrary to encapsulation. The solution is to provide a series of getter methods in the target, as getPassword()
to make the viewer get the user's password.
Although the "pull" approach may be considered to be more correct, but we think the user to make the theme of "push" information to come more easily. Since rewriting by update
()
adding the second parameter when the method is not feasible, then proceed from the other direction. Fortunately, PHP has such a characteristic in a method call, as long as the specified given parameter (argument) is not less than a mandatory parameter is defined (no parameter default values), the error will not PHP. A number of parameters passed in the method, by func_num_args
() 函数获取;
extra parameters can func_get_arg
()
function to read. Note that this function is counted from 0, i.e., 0 represents an argument. Using this trick, update
()
the method can func_get_arg(1)
receive one of an array of user information, with this array, you can know who sent the message, what is the new password. To save space, and information transmitted three classes is very similar, only one of which is given below of the source code, complete source code can be downloaded attachments obtained herein.
Listing 3. Email_Sender class source code
<?php
class EmailSender implements SplObserver {
public function update(SplSubject $subject) {
if (func_num_args() === 2) {
$userInfo = func_get_arg(1);
echo "向 {$userInfo['email']} 发送电子邮件成功。内容是:你好 {$userInfo['username']}" .
"你的新密码是 {$userInfo['password']},请妥善保管", PHP_EOL;
}
}
}
Finally, we write a test script test.php
. The recommended way to use the CLI php – f test.php
to execute the script, but the provision of the Content-Type
response header field text/plain
, the browser should be able to see the results displayed line by line (because there is no use <br />
to make line breaks but constant use PHP_EOL
, so do not set the Content-Type
words It can not correctly display the branch).
Listing 4. Test Script
<?php
header('Content-Type: text/plain');
function __autoload($class_name) {
require_once "$class_name.php";
}
$email_sender = new EmailSender();
$mobile_sender = new MobileSender();
$web_sender = new WebsiteSender();
$user = new User('[email protected]', '张三', '13610002000', '123456');
// 创建用户时通过 Email 和手机短信通知用户
$user->attach($email_sender);
$user->attach($mobile_sender);
$user->create($user);
echo PHP_EOL;
// 用户忘记密码后重置密码,还需要通过站内小纸条通知用户
$user->attach($web_sender);
$user->resetPassword();
echo PHP_EOL;
// 用户变更了密码,但是不要给他的手机发短信
$user->detach($mobile_sender);
$user->changePassword('654321');
echo PHP_EOL;
Listing 5. Running results
User::create
向 [email protected] 发送电子邮件成功。内容是:你好张三你的新密码是 123456,请妥善保管
向 13610002000 发送短消息成功。内容是:你好张三你的新密码是 123456,请妥善保管
User::resetPassword
向 [email protected] 发送电子邮件成功。内容是:你好张三你的新密码是 363989,请妥善保管
向 13610002000 发送短消息成功。内容是:你好张三你的新密码是 363989,请妥善保管
这是 1 封站内小纸条。你好张三,你的新密码是 363989,请妥善保管
User::changePassword
向 [email protected] 发送电子邮件成功。内容是:你好张三你的新密码是 654321,请妥善保管
这是 1 封站内小纸条。你好张三,你的新密码是 654321,请妥善保管
We see that user “
Joe Smith ”
through a variety of means to know what his password Yes.
Conclusion
For experienced developers, even without the use of SPL can also be easily Observer design pattern, but use SPL to bring greater efficiency, especially in combined SplObjectStorage
after registration and deletion of the observer by its proxy instance is completed. Although the use of "push" update the Observer, SplObserver
the update
()
method only accepts one parameter appears to fly in the ointment, or SPL built Observer design pattern support only through "pull mode" get notice, but by tips presented in this article can be make up. Therefore, SPL on the rapid realization Observer design patterns become the first choice.
Transfer from https://www.ibm.com/developerworks/cn/opensource/os-cn-observerspl/#ibm-pcon