dqoqnmb163241 2019-04-22 12:32
浏览 47
已采纳

从trait方法将资源分配给类属性

I've decided to write a trait that will be responsable to connect and disconnect from ftp using the php built in functions. I want to login, connect and disconnect to the host by using trait methods.

I need to use $this->conn from inside the instance of the class to use the ftp functions. The variable will hold the ftp connection. I want to assign to $this->conn the value returned from the connect trait method. I want to know if there is a way to call it inside the class.

I'm unable to get the $this variable inside the class that will use the trait. How can I access it inside the class?

<?php
trait ConnectionHelper
{
    public function connect(string $host, string $user, string $pwd)
    {
        $this->conn = ftp_connect($host);
        if ($this->conn && ftp_login($this->conn, $user, $pwd)) {
            ftp_pasv($this->conn, true);
            echo "Connected to: $host !";
        }
        return $this->conn;
    }
    public function disconnect()
    {
        return ftp_close($this->conn);
    }
}

class FTPManager
{
    use ConnectionHelper;
    private $url;
    private $user;
    private $password;

    /* Upload */
    public function upload(array $inputFile, string $dir = null)
    {
        if (!is_null($dir)) {
            ftp_chdir($this->conn, "/$dir/");
        }
        $upload = ftp_put($this->conn, $inputFile['name'], $inputFile['tmp_name'], FTP_BINARY);
        if ($upload) {
            echo 'File uploaded!';
        }
    }
}
?>

NB: Can be a good solution to call the connect method of the trait inside the class constructor?

<?php
class myclass{

use mytrait;

public function __construct(){
    $this->conn = $this->connect($host, $user, $pass);
}

}
?>
  • 写回答

1条回答 默认 最新

  • dongliang2058 2019-04-22 18:47
    关注

    Traits can be used to do what you want, but it would be better to actually use traits for what they can do: assign and read from class properties.

    In the trait, when you assign to $this->conn:

    $this->conn = ftp_connect($host);
    

    The property is defined for the class instances that use the trait. As such, no need to use $this->conn = $this->connect() because $this->conn will already contain the connection resource.

    So in the constructor, simply call the connect method:

    public function __construct()
    {
        $this->connect($host, $user, $pass);
        // $this->conn will now contain the connection made in connect()
    }
    

    No need to return $this->conn; in the trait. To make sure you free your resource, call disconnect() from FTPManager's destructor:

    public function __destruct()
    {
        $this->disconnect();
    }
    

    That being said, it is a rather quirky way of managing this. Having to manually call connect() in every class that use the trait is error prone, and might lead to maintainability issue (every one of those class need to be aware of ftp credentials, for instance, tightly coupling them to configuration).

    Thinking about it, these class instances are not dependant upon ftp credentials, they are dependant upon an active ftp connection. As such, it's way cleaner to actually ask for the ftp connection in the class's constructor, and not bother about calling connect() and disconnect() in every class that actually needs the ftp connection.

    We could think of a connection wrapper class that would greatly simplify things here:

    class FTPWrapper {
        private $connection;
        public function __construct(string $host, string $user, string $pwd)
        {
            $this->connect($host, $user, $pwd);
        }
        public function __destruct()
        {
            $this->disconnect();
        }
        public function getConnection()
        {
            return $this->connection;
        }
        private function connect(string $host, string $user, string $pwd): void
        {
            $this->connection = ftp_connect($host);
            if ($this->connection && ftp_login($this->connection, $user, $pwd)) {
                ftp_pasv($this->connection, true);
                echo "Connected to: $host !";
            }
        }
        private function disconnect(): void
        {
            ftp_close($this->conn);
        }
    }
    

    Then, inject that wrapper into whatever class that needs to use it.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?