创建单例——这真的正确吗?
我正在尝试创建自己的轻量级 OOP 方式来跟踪 PHP 框架中加载的文件及其适当的版本(尚未实现),以便将来能够轻松测试依赖关系问题。
这是我当前的代码,但作为 OOP 和模式的新手,我无法确定我是否已经完成了正确的单例:
class loadRegistry {
private static $registry = null;
private function __construct(){
if (is_null(self::$registry));
self::$registry = array();
}
public static function get() {
return self::$registry;
}
public static function set($filename){
if ( isSet( self::$registry[$filename]) AND !empty($filename) ) {
throw new Exception("File already loaded");
}
else self::$registry[$filename] = '';
}
}
loadRegistry::set('filename');
loadRegistry::set('filename2');
$reg = loadRegistry::get();
I am trying to create my own sort of lightweight,yet OOP way to keep track of loaded files and their appropriate versions (not yet implemented) in my PHP framework to be able to easily test dependency issues in the future.
Here's my current code, but being a total newcomer to OOP and patterns I am not able to determine if I have accomplished a proper Singleton or not:
class loadRegistry {
private static $registry = null;
private function __construct(){
if (is_null(self::$registry));
self::$registry = array();
}
public static function get() {
return self::$registry;
}
public static function set($filename){
if ( isSet( self::$registry[$filename]) AND !empty($filename) ) {
throw new Exception("File already loaded");
}
else self::$registry[$filename] = '';
}
}
loadRegistry::set('filename');
loadRegistry::set('filename2');
$reg = loadRegistry::get();
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
不,它不是单例。您实际上只是在玩静态属性。单例更像是这样的:
我不知道你是否可以在 PHP 中将构造函数设置为私有...我认为不能。静态类之间是有区别的$ 和一个单例。单例允许一次只有一个实例。对于静态类,您甚至不需要实例。此外,静态属性在类的所有实例之间共享(如果您创建实例)。
如果不需要实例来保存某些状态,通常可以使用静态类。
$:没有真正的静态类。只有成员才能定义为静态。我认为只有静态成员的类可以称为静态类。
No, it is not a singleton. You are actually only playing with static properties. A singleton would be more like this:
I don't know whether you can set the constructor as private in PHP... I think not.There is a difference between static classes$ and a singleton. A singleton allows to have only one instance at a time. For static classes, you don't even need an instance. In addition, static properties are shared between all instances of the class (in case you create an instance).
You normally use static classes if you don't need an instance to hold some state.
$: There are no real static classes. Only members can be defined as static. I'd say a class that has only static members can be called a static class.
您上面介绍的内容并不遵循单例模式。 Singleton 一次只允许该类存在一个实例(与定义静态对象相反,静态对象不会阻止您同时创建其他对象并将它们混合在一起)。
您可以在官方手册中阅读有关 PHP 中的单例模式的内容; http://php.net/manual/en/language.oop5.patterns.php 上面的手动示例
给出了一个简单的示例,但自从 PHP5 发布以来,我从未真正需要在 PHP 中使用 Singleton。它们在 iPhone 等设备上更有用,在这种设备上,您只需要一个接口来连接给定的硬件(例如屏幕)。但是,我想您可能会将它用于 PHP 应用程序中的数据库连接......
What you have presented above isn't following the pattern of a Singleton. A Singleton allows only a single instance of that class to exist at one time (as opposed to defining a Static object, which doesn't stop you from then creating other objects of the same time and getting them mixed up).
You can read about the Singleton Pattern in PHP in the official manual; http://php.net/manual/en/language.oop5.patterns.php
The manual example above gives a barebones example, but I've never really had the need to use a Singleton in PHP since PHP5 has been released. They are more useful on the devices such as the iPhone where you only want a single interface to a given piece of hardware - such as the screen. However, I guess you might use it for your DB connections in a PHP app...
这段代码看起来很奇怪 - 首先,构造函数永远不会被任何内部函数调用,并且不能在外部调用,因为它是私有的。它不是单例,因为单例实际上是作为对象创建的,而此类从来不是。
但是,如果您想要这样做,您可以使用这样的代码来创建分区的全局存储。
这是一个适合您的单例:
}
这是改进的 5.3+ 单例:
}
This code looks strange - first of all, the constructor is never called by any of the internal functions and can't be called externally since it's private. It's not a singleton since singleton is actually meant to be created as an object, while this class is never is.
You can, however, use code like this for creating compartmentalized global storage, if that is what you wanted to do.
Here's a singleton for you:
}
Here's improved 5.3+ singleton:
}
我发现这有点旧了。
我曾经只是为了单实例而使用单例,但是使用注册表,您不再需要静态。
另一方面是注册表的实现和使用方式,这将决定注册表解决方案是否良好。
因为我使用 MVC,只需为基本控制器传递一次注册表,为基本模型传递一次注册表,仅此而已。另一方面,如果设计需要经常传递注册表对象,那么这可能不是一个好主意。
基本思想是:
有一个注册表
一开始只是创建数据库类的一个实例,这样我们就不必费心创建连接等。使用两个数据库,直到我第一次需要它时才会创建连接。
$registry->dbManager = new dbManager();
将注册表对象传递给路由器、控制器和模型基类注册表随处可见。
$registry = My_Registry::singleton();
$registry->router = 新路由器($registry);
$registry->dbManager = new dbManager();
等等............
Db 类保持普通类,这只是 db 类的一部分
数据库管理器类
{
list($this->host,$this->user, $this->pass, $this->internal_db_name,$this->business_db_name ) = $db_conf;
<前><代码>}
//设置内部数据库连接
私有函数 setInternalDBCon()
{ debug('setInternalDBCon 被调用');
尝试{
# MySQL 与 PDO_MYSQL
$dbq="\"";
$this->Internal_db_con = 新
PDO("mysql:host=".$this->host.";dbname=".$this->internal_db_name ,$this->user, $this->pass,
数组(PDO::MYSQL_ATTR_INIT_COMMAND =>“设置名称utf8”));
PDO("mysql:host=".$this->host.";dbname=".$this->internal_db_name ,$this->user, $this->pass,
数组(PDO::MYSQL_ATTR_INIT_COMMAND =>“设置名称utf8”));
$this->Business_db_con->setAttribute (PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
捕获(PDOException $e)
{
echo '连接 MySQL 时出错:' .$e->getMessage();
}
<前><代码>}
/*检查一行是否以安全的方式存在以避免sql攻击*/
公共函数 uniqueRowExists($dbcon, $table,$col_name, $data)
{
//检查连接是否已设置
if($this->{$dbcon.'_db_con'}==null) //动态变量调用
$this->callMyFunc( 'set'.$dbcon.'DBCon'); //动态函数调用
…………等等……
........................etc
这就是我从 db 类调用公共函数的方式
//查询数据库
$result=$this->registry->dbManager->uniqueRowExists
('内部', 'internal_user', Array('uname','pass'), $input);
//可供选择的连接、要搜索的表、列、数组数据
这种方式进行搜索,任何地方都只有一个实例。
I see this is a bit old however..
I used to use singleton just for the sake of single instance, however with registry you don't need a static anymore.
On the other hand is how registry is implemented and used that will define if the registry solution is good.
Because I use MVC and only have to pass the registry once for the base controller and once for the base model and that's it all. On the other hand if one has a design that requires for passing the registry object very often the it might not be a good idea.
The basic idea is:
There is a registry
At the very begining is created just an instance of the database class, this way we don't bother with creating connections etc. I use two databases and no connection is created until the veri first time I will need it.
$registry->dbManager = new dbManager();
Passing the registry object to the router, controller and model base classes registry is seen everywhere.
$registry = My_Registry::singleton();
$registry->router = new router($registry);
$registry->dbManager = new dbManager();
etc..................
Db class stays normal class, this is just a part from the db class
class dbManager
{
list($this->host,$this->user, $this->pass, $this->internal_db_name,$this->business_db_name ) = $db_conf;
PDO("mysql:host=".$this->host.";dbname=".$this->internal_db_name ,$this->user, $this->pass,
array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
PDO("mysql:host=".$this->host.";dbname=".$this->internal_db_name ,$this->user, $this->pass,
array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
$this->Business_db_con->setAttribute (PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e)
{
echo 'Error connecting to MySQL: ' .$e->getMessage();
}
.......................etc....
.................etc
And this is how I call a public function from db class
//query the database
$result=$this->registry->dbManager->uniqueRowExists
('Internal', 'internal_user', Array('uname','pass'), $input);
//connection to choose from, table, coloumns, array data to search for
this way there is only a single instance anywhere.