我是OOP的初学者,现在我正在尝试编写一些PHP类来连接FTP服务器。
class ftpConnect {
private $server;
private $user;
private $password;
private $connection_id;
private $connection_correct = false;
public function __construct($server, $user = "anonymous", $password = "anonymous@mail.com") {
$this->server = $server;
$this->user = $user;
$this->password = $password;
$this->connection_id = ftp_connect($this->server);
$this->connection_correct = ftp_login($this->connection_id, $this->user, $this->password);
if ( (!$this->connection_id) || (!$this->connection_correct) ){
echo "Error! Couldn't connect to $this->server";
var_dump($this->connection_id);
var_dump($this->connection_correct);
return false;
} else {
echo "Successfully connected to $this->server, user: $this->user";
$this->connection_correct = true;
return true;
}
}
}
我认为现在这个班级的主体是微不足道的。
主要问题是我在理解OOP理念方面存在一些问题。
我想在每次运行代码时添加发送电子邮件。我已经下载了PHPMailer Class并用它扩展了我的课程:
class ftpConnect extends PHPMailer {...}
我添加了一些变量和方法,一切都按预期工作。
我想:为什么不在数据库中添加存储内容。每次用户运行上面的代码时,应将适当的信息存储在数据库中。
我可以编辑我的ftpConnect class
并添加连接到构造函数的数据库,以及其他一些更新表的方法。但是数据库连接和所有这些东西将来可以被其他类使用,所以它绝对应该在单独的类中实现。
但是我的“主”ftpConnect class
已经扩展了一个类,并且不能再扩展一个类。
我不知道如何解决这个问题。也许我的ftpConnect class
是复杂的,我应该以某种方式将它分成几个较小的类?
非常感谢任何帮助。
答案 0 :(得分:7)
对于初学者,我认为你的班级存在设计缺陷。你的构造函数正在做工作。这不是构造函数应该在适当的OOP中做的事情。您的构造函数应该只设置属性,您应该有一个单独的方法connect()
。
第二个ftpConnect
永远不应该延伸PHPMailer
。它们是两个完全不同的东西。阅读Liskov substitution principle SOLID principles中的dependency injection。
如果您的班级需要对数据库执行某些操作或需要发送邮件,则需要将这些实例注入您的类而不是扩展它们。这称为single responsibility principle,这样可以在以后轻松进行单元测试,因为您可以轻松使用模拟邮件程序类或模拟数据库类。
如果你想发送邮件,拥有数据库访问权限并使用FTP,你至少需要3个不同的(分离的)类(甚至可能需要为db等做一些映射)。基本上每个班级都应该有一个责任而一个只有一个。这称为Guide: Writing Testable Code。
对于一些一般参考文献,请参阅:
答案 1 :(得分:0)
这可能是一个关于继承的构成问题 看到这个 Prefer composition over inheritance? 只需使用类中的邮件程序对象,DB就可以使用它,而不是扩展其中任何一个的类。
class my_class
{
private $mailer;
public function __constructor()
{
$this->mailer = new Mailer();
}
}
答案 2 :(得分:0)
对于数据库存储部分,您可以创建一个单独的类,该类与您的数据库有连接。您可以通过它的构造函数将此类的实例传递给ftpConnect
类。为您的fptConnect
类提供一个属性,您可以在其中存储此新数据库对象,这样您就可以在整个ftpConnect
类中访问此对象。
你的ftpConnect
类当前有一个构造函数,它将返回true
或false
,不要让构造函数返回任何值,因为它需要返回一个实例ftpConnect类,您需要将其存储在变量中。因此,您可以使用单独的方法进行实际连接。所以你的班级看起来像这样。
class FtpConnect {
private $server;
private $user = "anonymous";
private $password = "anonymous@mail.com";
private $connection_id;
private $connection_correct = false;
//this will take care of the storage
private $database_handler;
public function __construct($server, $user, $password, $database_handler) {
$this->server = $server;
$this->user = $user;
$this->password = $password;
$this->database_handler = $database_handler;
//store the appropriate data, this will be done everything a new instance is created
$this->database_handler->store_data($data_to_store);
}
public function connect() {
//data to store, everytime a connection is made
$this->database_handler->store_data($data_to_store);
$this->connection_id = ftp_connect($this->server);
$this->connection_correct = ftp_login($this->connection_id, $this->user, $this- >password);
if ( (!$this->connection_id) || (!$this->connection_correct) ){
echo "Error! Couldn't connect to $this->server";
var_dump($this->connection_id);
var_dump($this->connection_correct);
return false;
} else {
echo "Successfully connected to $this->server, user: $this->user";
$this->connection_correct = true;
return true;
}
}
}
当然,这是一种可行的方法,可能会有更优雅的解决方案。 完成邮件的方式可以使用相同的概念来实现。
从外面看它会是这样的
$ftp = new FptConnect('server', 'user', 'password', new DbHandler('server', 'user', 'password', 'host'));
$ftp->connect();