I am writing a set of classes that handle simple file uploads with both ftp and ftps (not sftp) protocols.
Since the only difference between using ftp and ftps in PHP is the connect function, I thought that I could use a variable function in the form $connection_function($host);, where $connection_function has the either of the values ftp_connect() or ftp_ssl_connect().
I made an abstract class that decides which to use. Simplifying for clarity, I wrote:
abstract class uploader {
protected $connection_function;
public function __construct($protocol) {
if ( $protocol == "ftp" ) {
$this->connection_function = "ftp_connect";
} elseif ( $protocol == "sftp" ) {
$this->connection_function = "ftp_ssl_connect";
}
}
public function upload($host, $file, ... ) {
$conn = $this->connection_function($host);
}
}
class ftp_uploader extends uploader {
parent::__construct("ftp");
}
class ftps_uploader extends uploader {
parent::__construct("ftps");
}
I get the error
PHP Fatal error: Call to undefined method ftp_uploader::connection_function()
Which obviously comes from
public function upload($host, $file, … ) {
$conn = $this->connection_function($host);
}
So it occurs to me that I’ve written a variable method instead of a variable function, which is apparently not allowed (or treated as I expect it to be) in PHP.
Can I do what I want? The abstract class handles all of the ftp functions, and I would like to avoid duplicating code over two classes.
Edit Now that I’ve looked at it a bit, I see that I can just put the protocol decision in the conection method itself:
public function upload($host, $file, ... ) {
if ( $protocol == "ftp" ) {
$conn = ftp_connect($host);
} elseif ( $protocol == "sftp" ) {
$cont = ftp_ssl_connect($host);
}
}
But still I wonder, is there a way to do my variable methods? As it is, I still have to duplicate my expection-throwing error handling and any other code I might want to put inside those if-blocks.
As far as the interpreter knows, you’re trying to call that function, not use is as a variable:
Instead, try this:
And as crashspeeder mentions, you can also use
call_user_func(), here’s a slightly modified version of his answer:For this specific use case, that’s likely the best solution, as you can easily pass on the arguments.