I created an ssh2 wrapper. I have read that a constructor should not fail, so the ssh2 connection is not done in the wrapper, but by a method connect(). My question is: how do I make sure that connect() is called? I also really only need it to be called once.
class uploader {
private $user; private $pass; private $host;
private $ssh = null; private $sftp = null;
public function __construct($host, $user, $pass) {
$this->host = $host; $this->user = $user; $this->pass = $pass;
}
public function connect() {
if ($this->ssh === null) {
$this->ssh = ssh2_connect($this->host);
ssh2_auth_password($this->ssh, $this->user, $this->pass);
$this->sftp = ssh2_sftp($this->ssh);
}
}
}
What is the best way to ensure that connect() is called? Should the application call it?
$ssh = new uploader('host', 'user', 'pass');
$ssh->connect();
Or in the class methods?
...
public function upload($source, $dest, $filename) {
$this->connect();
...
}
public function delete($file) {
$this->connect();
...
}
Neither of these seems ideal.
I also thought about making a static method that would wrap the constructor and connect, but then the constructor would have to be private and I have also read that static methods are undesirable (mostly just for unit testing).
I have also read that static methods are undesirable (mostly just for unit testing).
Static methods are undesirable for some things, but factory methods isn't one of them. They make perfect sense there and do not impact unit testing. So, go ahead and make a static factory method.
The easiest way is to call connect() in your constructor and be sure to make a destructor function to disconnect your connection.
Related
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);
}
}
?>
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.
I read many posts and blogs about Singleton and database connection. What I understand from the singleton definition is that you can use it on any class object that is instantiated many times while staying intact.
I have a web application, and I was wondering if I could implement Singleton for database connection
Here is what I have under the DatabaseGateway class:
class DatabaseGateway
{
private $DBConnection;
private $serverName;
private $userName;
private $password;
private $databaseName;
public function __construct() {
//not done
}
public function getDBConnection() {
return $this->DBConnection;
}
public function openDBConnection() {
$this->DBConnection = new mysqli($this->serverName, $this->userName, $this->password, $this->databaseName);
}
public function closeDBConnection() {
mysqli_close($this->DBConnection);
}
The method OpenDBConnection is used when users log in in the UserGateway class. I was wondering if it is a good idea, and if it possible, to make openDBconnection into a singleton, while everyone has their own account and password.
I have a "static" class which connects to database and has various functions. The current base layout is as follows:
class DB {
private static $con;
private function __construct() {};
private static function init() {
if(is_null(self::$con) {
// Initialize database connection
}
}
public static someMethod1() {
self::init();
// Do stuff
}
public static someMethod2() {
self::init();
// Do stuff
}
public static someMethod2() {
self::init();
// Do stuff
}
}
My intention is to be easily be able to call these methods as: DB::someMethod1(). However, as you can see, I am having to cehck for initialization at every method beginning. Is this a good coding practice? Is there a better design pattern available? Initially I thought of builder pattern but that doesn't really fit here in my opinion.
It looks like you are trying to ensure that there is a single instance of your DB class AND also that the instance is available as a single, globally available constant.
I'd recommend separating those two concerns in order to simplify the implementation.
First, I'd focus on getting the database access object right. Plain objects are simpler to test and inject as dependencies than static functions. For example,
class DBThing
{
private $con;
public static function build()
{
return new static('theconnection');
}
function __construct($con)
{
$this->con = $con;
}
public function someMethod1()
{
echo "someMethod1: $this->con\n";
}
public function someMethod2()
{
echo "someMethod2: $this->con\n";
}
public function someMethod3()
{
echo "someMethod3: $this->con\n";
}
}
Gives you an object you can easily test and replace with alternate implementations if needed.
Second, I'd focus on the object lifecycle and making it discoverable in the application.
If you're really OK with a single instance and the global state that implies, then something like this gets you close to the interface you asked for in your original post.
$DB = DBThing::build();
$DB->someMethod1();
$DB->someMethod2();
$DB->someMethod3();
In general, I discourage global state but I'd have to know more about your application to know if it's appropriate in your case.
I just wrote a simple db class for a coding test. Take a look at how I used here: https://github.com/TheRealJAG/Valuation-Vision-Full-Stack-Test/blob/master/classes/db.php
class DB
{
private static $instance = null;
private $db;
private $host = '';
private $username = '';
private $password = '';
private $database = '';
private function __construct()
{
$this->db = new mysqli($this->host, $this->username, $this->password, $this->database);
if ($this->db->connect_error) {
throw new Exception("Connection to the mysql database failed: " . $this->db->connect_error);
}
}
public static function connection()
{
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance->db;
}
}
I'm 100% sold on the approach, but with the time I had for the test this is what I wrote. My biggest concern was that I only had 1 db connection open.
I have a method in connection class which returns a dbconnection instance so I can make query with that.
class Connection
{
public $dbh; // handle of the db connexion
private static $instance;
public $resultBool;
public $connectedDbName;
public $resultString;
public $directed;
public static $deviceid;
private function __construct()
{
$this->dbh = new PDO('mysql:host=localhost;dbname=webfilter;port=3306;connect_timeout=15', 'root', 'company');
$this->dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$this->directed = false;
$this->resultBool = true;
}
public static function getConnection()
{
if (!isset(self::$instance))
{
$object = __CLASS__;
self::$instance = new $object;
}
...
return self::$instance;
}
At first request, there is a connection required so I step into this connection function that's ok. but why I need to make connection again even there is so obvious I will use same connection.. it seems cause performance issue..
here is my function which makes real job. I use dbObject to make queries on db, but for each time I need to connection instance(getconnection) to do it.
$dbObject = Connection::getConnection();
$request = $dbObject->dbh->prepare($sql);
$request->bindParam(':username', $username, PDO::PARAM_STR);
is it possible to save existing connection for next request of same users or another way to pass connection operation
You already use the singleton pattern. This is only working for multiple connections in one request. For every request this class creates a new object of the connection class. A PDO instance can't be serialized or unserialized or saved on a session. I think there is no way at the moment to do this.
I've trying to learn PHP OOP and have made some research on how to make a global database class to use around in my project. From what I've seen the most appropriate pattern available is a singleton which would ensure that only one database connection are present at all times. However as this is my first time working with the Singleton pattern, I am not sure that I have made it right.
Is this a proper singleton? Will this code ensure one database connection only? Is there any way I can test this? (Learn a man to fish and he will have food for the rest of his life...)
I am using redbean as my ORM and here's how I set it up plainly:
require_once PLUGINPATH.'rb.php';
$redbean= R::setup("mysql:host=192.168.1.1;dbname=myDatabase",'username','password');
I've made the following script based upon this source, as my own singleton Database class;
class database {
private $connection = null;
private function __construct(){
require_once PLUGINPATH.'rb.php';
$this->connection = R::setup("mysql:host=192.168.1.1;dbname=myDatabase",'username','password');
}
public static function get() {
static $db = null;
if ( $db === null )
$db = new database();
return $db;
}
public function connection() {
return $this->connection;
}
}
Thanks!
The instance variable needs to be a static member of the class. I haven't tested this code, but it should work. Connection should probably be static too. With this code, you will have one instance of your database class, and one instance of the connection. It is possible to do this without connection being static, but making it static will ensure there is only one connection instance. I also changed the literal names of the class to php magic constants. This make your code more maintainable. If you change the name of your class down the road, you won't have to go and find all of the literal instances of the old class name in your code. This may seem like overkill now, but trust me, as you work on more and more complex projects, you will appreciate the value.
class database {
private static $connection = null;
private static $db;
private function __construct(){
require_once PLUGINPATH.'rb.php';
self::$connection = R::setup("mysql:host=192.168.1.1;dbname=myDatabase",'username','password');
}
public static function get() {
if ( !(self::$db instanceof __CLASS__) ) {
$klass = __CLASS__; // have to set this to a var, cant use the constant with "new"
self::$db = new $klass();
}
return self::$db;
}
public function connection() {
return self::$connection;
}
}
You're singleton is almost correct.
The private member (no pun intended) $connection needs to be static as well. You might go with the following too:
class database {
private static $instance = NULL;
protected $conn;
private function __construct() {
$this->conn = mysql_connect( ... );
}
public static function init() {
if (NULL !== self::$instance)
throw new SingletonException();
self::$instance = new database();
}
public static function get_handle() {
if (NULL === self::$instance)
; // error handling here
return self::$instance->conn;
}
}