PHP-OOP扩展了两个类?

时间:2012-10-13 21:28:06

标签: php oop

我是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是复杂的,我应该以某种方式将它分成几个较小的类? 非常感谢任何帮助。

3 个答案:

答案 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类当前有一个构造函数,它将返回truefalse,不要让构造函数返回任何值,因为它需要返回一个实例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();