Pardon any mistakes in verbiage, I am trying to learn classes.
Once an object has been instantiated, I understand that methods from that class become available to me. My question is, how am I able to run methods from a class other than the instantiated one on said object?
Specifically:
class image {
public static function create() {
$image = new Imagick($file);
$image -> image::autoRotate($image);
...
}
public static function autoRotate($image) {
...
}
}
the line $image -> image::autoRotate($image) yields the error, and I understand the syntax and/or my understanding are at fault. Can someone kindly help me understand how to accomplish this please?
Because the the image class isn't actually a property of the $image object, you don't need to use the $image -> syntax to perform that operation. Since autoRotate() is a static function, it can be called just from the class accessor image::autoRotate($image);
class image {
public static function create() {
$image = new Imagick($file);
image::autoRotate($image); // removed $image ->
...
}
public static function autoRotate($image) {
...
}
}
public static function can be called directly by classname::funcname, no need to instantiate an object first. In your case:
class image {
public static function create() {
$image = new Imagick($file);
image::autoRotate($image);
...
}
public static function autoRotate($image) {
...
}
}
Try to replace line ..
$image -> image::autoRotate($image);
with this one..
self::autoRotateImage($image);
Related
I'm struggling with this for a while now and since Google has tons of results on this issue i'm wondering what i'm doing wrong since none of the solutions seems to work for me.
I have two classes File and Image. I let the File class decide wether the input is an image or another type of file. When the file is an image i want to pass that file to the Image class to process it.
So far i have this
Class File{
public $file;
function __construct($input){
$this->file = $input;
}
public function getFileType(){
// determine filetype of $this->file
return 'image';
}
}
Class Image Extends File{
function __construct(){}
public function test(){
return $this->file;
}
}
$file = new File('file.jpg');
if($file->getFileType() == 'image'){
$image = new Image;
echo $image->test();
}
But this doesn't output anything. How can i access the value of the constructor argument of the parent class in the inherited class? Calling parent::__construct(); in the child constructor class (as mentioned here) gives me a missing argument warning and this one (call_user_func_array(array($this, 'parent::__construct'), $args); in the child constructor) also doesn't work.
What am i missing?
First you need to understand that $image and $file in your code are 2 different objects.
$image knows nothing about $file and vice versa.
With your code design the solution can be:
Class File {
public $file;
function __construct($input){
$this->file = $input;
}
public function getFileType(){
// determine filetype of $this->file
return 'image';
}
}
Class Image Extends File{
function __construct($input)
{
parent::__construct($input);
// after that you have `$this->file` set
}
public function test(){
return $this->file;
}
}
$file = new Image('file.jpg');
if ($file->getFileType() == 'image'){
echo $file->test();
}
But such approach is messy. You create object of class Image and after creation you make sure that it is really image. I suppose you need to use something like fabric pattern and generate object of proper kind in a File class.
I have a class like this:
// file /models/person.php
class Person
{
public function create_path()
{
self::log();
path_helper($this); //a global function in other php file
}
public function log()
{
echo "trying to create a path";
}
}
This is the way how Person is instanciated:
//file /tools/Builder.php
include('/models/Person.php');
class Builder
{
public function build()
{
$type = 'Person';
$temp = new $type();
$temp->create_path();
}
}
As you note in Person class, I am calling the object in question with $this reference. But this is not correct because an error is showed:
Message: Undefined variable: this
I suppose that $this reference point to other object or it is unable to work because the object is created from another script. Also, I tried to use self because there was not problem calling methods with that, but as parameter I get:
Message: Use of undefined constant self - assumed 'self'
So, can you guide me to the right direction?
I tested your code out for myself, with a few minor changes. It appears to work properly.
Changed self::log() to $this->log()
Added global function path_helper (I have no idea what this does)
PHP
function path_helper(Person $object)
{
var_dump($object);
}
class Person
{
public function create_path()
{
$this->log();
path_helper($this); //a global function in other php file
}
public function log()
{
echo "trying to create a path";
}
}
class Builder
{
public function build()
{
$type = 'Person';
$temp = new $type();
$temp->create_path();
}
}
$Build = new Builder();
$Build->build();
Result
trying to create a path
object(Person)[2]
Your code is correct and your going in the right direction.
You should call the log method like this:
$this->log();
because using self:: is reserved for static methods.
Also, try calling the path_helper function like this:
path_helper(self);
Hope I could help you. Couldn't test it, but it should work.
I try to extend the CheckfrontAPI class with my new class.
In my case I use the Singleton pattern in order to load only one instance at a time of my class and I get that error
Fatal error: Declaration of CheckFrontIntegrator::store() must be compatible with that of CheckfrontAPI::store() in /home/my_web_site/public_html/wp-content/plugins/checkfront/class/Checkfront_Integration.php on line 83
Any idea on how to solve that issue ?
Here is the CheckfrontAPI source code : https://github.com/Checkfront/PHP-SDK/blob/master/lib/CheckfrontAPI.php
And here is my class that extends that class:
<?php
class CheckFrontIntegrator extends CheckfrontAPI
{
private static $instance = null;
public $tmp_file = '.checkfront_oauth';
final protected function store($data = array())
{
$tmp_file = sys_get_temp_dir() . DIRECTORY_SEPARATOR. $this->tmp_file;
if(count($data))
{
file_put_contents(
$tmp_file,
json_encode(
$data,
true
)
);
}
elseif(is_file($tmp_file))
{
$data = json_decode(
trim(
file_get_contents(
$tmp_file
)
),
true
);
}
return $data;
}
public function session($session_id, $data = array())
{
$_SESSION['checkfront']['session_id'] = $session_id;
}
public static function instance($data)
{
if(!isset(self::$instance))
{
self::$instance = new CheckFrontIntegrator($data);
}
return self::$instance;
}
public function __construct($data)
{
if(session_id() == '')
{
session_start();
}
parent::__construct($data, session_id());
}
}
?>
And I initiate the new instance of that class like that:
$this->checkfront_integrator = CheckFrontIntegrator::instance($args);
where args are all the important information needit by the class to initiate a new object
AFTER EDIT
I have change my method store from:
final protected function store($data = array())
....
to
protected function store($data)
....
and the problem still occure :(
CheckfrontAPI is an abstract class? in this case your CheckFrontIntegrator::store() arguments count must be identical to original declaration
EDIT
I see on github
abstract protected function store($data);
your override must be:
protected function store($data) {
}
You are extending CheckfrontAPI. CheckfrontAPI has a method store(). If you override that method you must do it properly.
Post the code of CheckfrontAPI and your class Checkfront_Integration: when can understand what's the problem.
When you want to extent the functionality of an existing class by writing your own class and the class you are extending is is an abstract one, you'll need to make sure that the function calls are compatible.
What does this mean?
If the class you are extending has this function call for example :
function walk($direction, $speed = null);
Then you will have to honor the function signature in your implementation - that means you'll still have to have to pass two function arguments in your version.
You will not be able to alter is to be like this :
function walk($direction, $speed, $clothing);
OK. here is what I'm trying to do:
class Image{
public $_image;
public $_extension;
public $_mime;
public $_size;
public $_location;
public $_description;
public function __construct($image, $location){
$this->_image = $image;
$this->_location = $location;
$this->_extension = getExtension();
$this->_mime = getMime();
$this->_size = getSize();
}
private functions fallow.....
}
But I keep getting an internal server error when I try to run it. When I comment out the method calls it works. So the question is can I call methods from inside the constructor or am I doing something wrong with the methods.
Do your functions getExtension, getMime and getSize exist? Are they methods on this class? If they are methods, they need to be called with $this->... as in
$this->_extension = $this->getExtension();
If they are not methods, and are functions, you need to make sure the files that contain/define them are loaded before you run the constructor.
Well ..this fragment of code will work as expected:
class Foo
{
protected $secret = null;
public function __construct( $data )
{
$this->secret = $this->makeSecret($data);
}
public function makeSecret( $data )
{
return md5( $data );
}
}
$bar = new Foo( 'lorem ipsum' );
That is not a problem.
But you should know, that is considered to be a bad practice - to do computation/work in the constructor. It makes that class practically untestable. Instead, if you need to perform some computation before "releasing" the object to the rest of the code, you should use a factory. Something along the lines of :
class ImageFactory
{
public function build($image, $location)
{
$instance = new Image($image, $location);
$instance->prepare();
return $instance;
}
}
The class would need some changes:
class Image
{
protected $_image; // you were leaking abstraction
protected $_extension;
protected $_mime;
protected $_size;
protected $_location;
protected $_description;
public function __construct($image, $location)
{
$this->_image = $image;
$this->_location = $location;
}
public function prepare()
{
$this->_extension = $this->getExtension();
$this->_mime = $this->getMime();
$this->_size = $this->getSize();
}
private functions fallow.....
}
Now when you need to create new object you do:
$factory = new ImageFactory;
$image = $factory->build( $file, '/uploads/' );
Of course the instance of ImageFactory can be reusable, and if all your images use the same $location, then you would pass that variable to factory at the initialization. And the factory would be able to "remember it" and pass to all the images it creates:
$factory = new ImageFactory('/uploads/');
$img1 = $factory->build( $file );
$img2 = $factory->build( $something_else );
This is actually how one should deal with creating multiple objects, which all need access to same DB connection instance.
Yes, you can call methods from within the constructor. Remember that the __construct() magic method was implemented in PHP 5. Prior to that, you created a function named the same as your class which acted as your constructor so depending on your PHP version, that could be a problem.
Additionally, the function calls you are making, are they in the class or external? If they are inside the class you need to call them this way:
$this->_extension = $this->getExtension();
You didnt specified what error you are expiriencing clearly. But try calling you class methods even inside the class using this keyword, otherwise it would not work:
public function __construct($image, $location)
{
$this->_image = $image;
$this->_location = $location;
$this->_extension = $this->getExtension();
$this->_mime = $this->getMime();
$this->_size = $this->getSize();
}
Would be a better idea to post your code for the methods you wrote. There could be something wrong within them as well. Possibly forgetting to return a result or something...
I have a simple question regarding PHP Classes.
Multiple times I have seen other class-frameworks etc use method calls like.
$post->data->text();
I like this functionality, rather than just doing something like this.
$post->dataReturnAsText();
But i'm not quite sure how they created this functionality to have perhaps a 'sub-method'? Hope someone can point me in the right direction....
The example you provide has nothing special:
<?php
class Post{
public $data;
}
class Data{
public function text(){
}
}
$post = new Post;
$post->data = new Data;
$post->data->text();
However, you've probably found it in the context of method chaining (very popular in JavaScript libraries):
<?php
class Foo{
public function doThis(){
return $this;
}
public function doThat(){
return $this;
}
}
$foo = new Foo;
$foo->doThis()->doThat()->doThis();
In this case, data is simply a attribute of the class, and it contains another object:
class data
{
public function text()
{
}
}
class thing
{
public $data;
}
$thing = new thing();
$thing->data = new data();
$thing->data->text();
its probably a just that the "data" is a a public property of $post containing an object wth a text property for example :
class Textable {
public $text;
function __construct($intext) {
$this->text = $intext;
}
}
class Post {
public $data;
function __construct() {
$data = new Textable("jabberwocky");
}
}
this will allow you to do :
$post = new Post();
echo( $post->data->text ); // print out "jabberwocky"
of course the right OOP way is to make the property private and allow access useing a getter function but that besides the point...