With or without $this in PHP [duplicate] - php

This question already has answers here:
What does the variable $this mean in PHP?
(11 answers)
Closed 4 years ago.
I am new in OOP PHP. Why do we have to use $this reference, when the code is working without it too?
If I delete both $this (before ->sql) from this code fragment, the modification is work as well. Although I read about it, I still don't understand what is $this in the given method.
class blogs{
private $servername = "localhost";
private $username = "root";
private $password = "";
private $dbname = "asd";
private $conn = "";
private $result = "";
private $row = "";
private $sql = "";
public function cmd_update(){
$this->sql = "UPDATE
blogs
SET
`name` = '".$_GET['input_name']."',
`date` = '".date('Y-m-d H:m:s')."',
WHERE
id = ".$_GET['input_modifying_id']."
";
if ($this->conn->query($this->sql) === TRUE) {
echo "Successfully modified!";
} else {
echo "Modifying Unsuccessful!";
}
}

$this refers to the current object - in this case, $this is shorthand for the blogs class.
Let's take this example class:
class Foo
{
protected $a;
public function __construct($a)
{
$this->a = $a;
}
public function getA()
{
return $this->a;
}
}
Here I'm simply assigning $a to whatever gets passed to a new Foo instance and creating a public-accessible function to return $a.
We use $this to refer to what we're currently in, $this->a is the protected $a.
This is a really handy feature for developers as it means we don't have to create our own way of getting the instance without redeclaration. It also means we can use templating for easier use. E.g.
class Foo
{
public function sayHi()
{
return 'hello world';
}
}
and
class Bar extends Foo
{}
because public functions are well.. public we can access parent classes with $this:
<?php
$bar = new Bar();
echo $bar->sayHi(); # will output hello world
It also means we can create a set of generic functions and properties relating to the object to allow more dynamic code. Take these blogs:
title = hello world
content = hello world
img = /path/to/img.jpg
title = what we did last summer
content = played in the park
img = /path/to/another/img.jpg
We can have a blog class like this:
class GenericController
{
# pretend we've done some PDO set up here where we set new PDO to $this->pdo
public function load($id)
{
$sql = 'SELECT * FROM `blogs` WHERE `id` = :id';
$res = $this->pdo->prepare($sql);
$res->execute(array(':id' => $id));
return (object) $res->fetch(PDO::FETCH_ASSOC);
}
}
class Blog extends GenericController
{
protected $id;
protected $data;
public function __construct($id)
{
$this->id = $id;
}
protected function loadData()
{
$this->data = $this->load($this->id);
}
public function getTitle()
{
return $this->data->title;
}
public function getContent()
{
return $this->data->content;
}
public function getImg()
{
return $this->data->img
}
}
$blogOne = new Blog(1);
$blogTwo = new Blog(2);
echo $blogOne->getTitle(); # will output hello world
echo $blogTwo->getTitle(); # will output what we did last summer
further reading:
For MySQL Injection reasons (your code is currently open to said injection):
PDO
PDO Prepared Statements
For OOP:
The Basics
Visibility
And $this from the docs itself (can be found via The Basics link):
The pseudo-variable $this is available when a method is called from within an object context. $this is a reference to the calling object (usually the object to which the method belongs, but possibly another object, if the method is called statically from the context of a secondary object). As of PHP 7.0.0 calling a non-static method statically from an incompatible context results in $this being undefined inside the method

$this is a reference of current calling object or we can say that object in use. When you work with multiple instance of class your code base will be manageable for different instances. Also the visibility allows that what you want to keep private or public. And $this will work throughout the object life once you set you can accept anywhere in the object/class scope not limited to the function.

Related

PHP object composition - access owner class' property without passing down arguments?

I have asked this question beforehand, but I might have worded it poorly. I did not get the answer.
I have an Image class that always creates an instance of an Id class when it constructs. Each Image always has an Id, and when Image is destroyed, the Id is destroyed as well. As far as I understand, this is called Object Composition.
My Image class (here: $myImage), during intialization/construction, creates a property: $this->id = new Id();
I want $this->id to be able to access a property of $myImage. Simple example:
class Image {
public $fileSize;
public $id;
const validMimeTypes = array('image/png', 'image/jpeg');
public function __construct($fileSize = 0.0) {
$this->fileSize = $fileSize;
$this->id = new Id();
}
}
class Id {
public function echoMe() {
echo $creatorInstance->fileSize;
echo creatorClass::validMimeTypes;
//This is what I'd like to know how to do
}
}
$myImage = new Image();
$myImage->id->echoMe();
I would like to know how an Id can access one of its creator's properties.
I would like to know if there are differences between accessing class constants and object properties if it turns out to not be obvious.
For example, Id might need the creator object's fileName and fileSize to generate a hash, or it might need its validMimeTypes, which could be a const array describing that class.
I don't mind knowing if this is has better alternatives - in fact, I'm curious - but first of all I'd like to know how to achieve this without passing down arguments during the __construct() stage.
First, you shouldn't use public attributes, because it breaks encapsulation.
Take a look at the code below. You can pass $this to the target class, and be able to access its methods and attributes:
class A
{
public function __construct()
{
$this->b = new B($this);
}
public function func()
{
echo "hello, world!";
}
}
class B
{
private $a;
public function __construct(A $a)
{
$this->a = $a;
echo $a->func();
}
}
$a = new A;
It will display hello, world!
So, in your case, just use $this->id = new Id($this); and create a constructor to Id class that will set the Image instance to a class attribute.

PDO: Fetch class option to send fields to constructor as array

I am wondering whether or not it is possible to elegantly map the results of a PDO query to an array member in a class rather than have them floating about as public properties of that object.
Say I have the (condensed) following:
class DBObject {
protected
$record = array();
function __construct(array $record) {
if(!empty($record)) {
$this->loadRecord($record);
}
}
}
Ideally, I want to call the constructor with an array of values passed from the database, rather than use __set or any other weird methods. So using PDO's existing API would be great.
My rough get_all function at the moment has got this far:
static function get_all() {
$class = get_called_class();
$results = DB::factory()->query('SELECT * FROM ' . $class . ' ORDER BY ID');
$results->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, $class);
return $results;
}
NB: I'm running PHP 5.3 and MySQL through PDO, and already know this problem is solveable using __set, but I explicitly want to avoid using it in favour of something more performant.
You don't need to pass arguments to a constructor to make a class with private members using PDO::FETCH_CLASS. You can do something like this:
<?php
class Songs
{
private $artist;
private $title;
public function __construct()
{
}
public function get_artist()
{
return $this->artist;
}
public function get_title()
{
return $this->title;
}
private function set_artist($artist)
{
$this->artist = $artist;
}
private function set_title($title)
{
$this->title = $title;
}
}
I'm actually doing that on a demo site that I built. It works just fine with PDO::FETCH_CLASS. By default, FETCH_CLASS creates objects by populating the fields BEFORE the constructor. Think of it as bypassing the constructor. And it will do this with private members.
If you'd rather pass arguments to the constructor you can do your query like this:
$obj = $statement->fetchALL(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, 'Songs', $params);
In that case your constructor would look like this:
public function __construct($params)
{
$this->artist = $params[0]['artist'];
$this->title= $params[0]['title'];
}
Removed previous code
Right, can't you do something like this:
class DBObject {
protected $record = array();
function __construct($record = null) {
if(null === $record){
$obj_vars = get_object_vars($this);
$cls_vars = get_class_vars(get_class($this));
$this->$record = array_diff_key($obj_vars, $cls_vars);
}else{
$this->record = $record;
}
}
}
The problem with this however is that the values are still available as public members.
But what it will do is compare 'pre-defined' (class) members to the actual (object) members.
Since PDO will create new members in the object you can use array_diff_key to get the 'new' members.
Yes, this will still not pass them through your constructor.
How about using magic __set() method:
<?php
class MyClass
{
protected $record = array();
function __set($name, $value) {
$this->record[$name] = $value;
}
}
$pdo = new PDO("mysql:host=localhost;dbname=db", 'user', 'password');
$results = $pdo->query('SELECT * FROM table');
$results->setFetchMode(PDO::FETCH_CLASS, 'MyClass');
PHP will call this magic method for every non-existent property passing in its name and value.

PHP OOP: Accessing Variables

I have the following "Student" Class:
class Student {
public $user_id;
public $name;
public function __construct($user_id) {
$info = $this->studentInfo($user_id);
$this->name = $info['name'];
$this->is_instructor = $info['is_instructor'];
$this->user_id = $info['id'];
}
public static function studentInfo($id) {
global $db;
$u = mysql_fetch_array(mysql_query("SELECT * FROM $db[students] WHERE id='$id'"));
if($u) {
return $u;
}
}
public static function getCoursesByInstructor() {
global $db;
return mysql_query("SELECT courses.*, course_types.name FROM $db[courses] as courses
JOIN $db[course_types] as course_types ON courses.course_type_id=course_types.id
WHERE instructor_id='$this->user_id'");
}
}
I'm trying to do:
$u = new Student(1);
$courses = $u->getCoursesByInstructor();
But am getting the following error:
Fatal error: Using $this when not in object context in /Applications/MAMP/htdocs/flight1/phpincludes/classes/students.class.php on line 54
You're getting that error because you're function is a static function, and therefore you cannot use the $this pointer within it because it supposed to point to an object. So just remove the static keyword from your function definitions.
You are using static methods non-statically. Static methods are only bound to its class, but not to an object, thus $this is not available. This especially means, that $this->userid, that you use in getCoursesByInstructor(), is not valid. I recommend to make the method non-static.
public function getCoursesByInstructor() { /* your code here */ }
Remove the static keyword from the functions you declared inside your Student class.
The static keyword is, simply put, used to indicate a function that is accessible without the need of creating an instance of that class. On the other hand, $this is used to refer to class instance variables. That's why those two don't go well togheter, you're trying to access an instance variable (by using $this) in a static context.
The issue with your code is you are requesting $this inside your static function. See this. You have $this->user_id inside the query.
return mysql_query("SELECT courses.*, course_types.name FROM $db[courses] as courses
JOIN $db[course_types] as course_types ON courses.course_type_id=course_types.id
WHERE instructor_id='$this->user_id'");
To fix this issue you have to modify this function. I can suggest you following way.
public static function getCoursesByInstructor($userID) {
global $db;
return mysql_query("SELECT courses.*, course_types.name FROM $db[courses] as courses
JOIN $db[course_types] as course_types ON courses.course_type_id=course_types.id
WHERE instructor_id='$userID'");
}
And you have to change your other functions with the same theory.
Cheers !

PHP constructors and static functions

I'm a bit confused on how constructors work in PHP.
I have a class with a constructor which gets called when I instantiate a new object.
$foo = new Foo($args);
__construct($params) is called in the class Foo and it executes the appropriate initialization code.
However when I use the class to call a static function, the constructor is called again.
$bar = Foo::some_function(); //runs the constructor from Foo
This causes the constructor to execute, running the object initialization code that I intended only for when I create a new Foo object.
Am I missing the point of how constructors work? Or is there a way to prevent __construct() from executing when I use the class to make static function calls?
Should I use a "factory" function instead to do the object initialization? If so, what's the point of the constructor then?
::EDIT::
I have a form where users can upload photos to an album (create_photo.php) and an area where they can view the album (view_photos.php). Upon form submit:
$photo = new Photo($_FILES['photo'], $_POST['arg1'], ect..);
The Photo constructor creates and saves the photo. However in view_photo.php, when I call:
$photo = Photo::find_by_id($_POST['id']) //user-defined function to query database
This is causing Photo's constructor to run!
I see nothing that replicates your question.
See Demo: http://codepad.org/h2TMPYUV
Code:
class Foo {
function __construct(){
echo 'hi!';
}
static function bar(){
return 'there';
}
}
echo Foo::bar(); //output: "there"
Assumption
PHP 5.x
Different goals, different path
create a new instance of a class (object)
class myClassA
{
public $lv;
public function __construct($par)
{
echo "Inside the constructor\n";
$this->lv = $par;
}
}
$a = new myClassA(11);
$b = new myClassA(63);
because we create a new object PHP calls:
__construct($par);
of the new object, so:
$a->lv == 11
$b->lv == 63
use a function of a class
class myClassB
{
public static $sv;
public static function psf($par)
{
self::$sv = $par;
}
}
myClassB::psf("Hello!");
$rf = &myClassB::$sv;
myClassB::psf("Hi.");
now $rf == "Hi."
function or variabiles must defined static to be accessed by ::, no object is created calling "psf", the "class variable" sv has only 1 instance inside the class.
use a singleton created by a Factory (myClassA is above)
class myClassC
{
private static $singleton;
public static function getInstance($par){
if(is_null(self::$singleton)){
self::$singleton = new myClassA($par);
}
return self::$singleton;
}
}
$g = myClassC::getInstance("gino");
echo "got G\n";
$p = myClassC::getInstance("pino");
echo "got P\n";
Using the factory (getInstance) the first time we construct a new object having $par set to gino.
Using the factory the second time $singleton has already a value that we return. No new object is created (no __construct is called, less memory & cpu is used).
The value of course is an object instanceOf myClassA and don't forget:
myClassC::$singleton->lv == "gino"
Pay attention to singletons:
What is so bad about singletons?
http://www.youtube.com/watch?v=-FRm3VPhseI
By my answer I don't want promote/demote singleton. Simply from the words in the question, I made this calc:
"static"+"__construct"="singleton"!
Here is my workaround:
I put method construct() in static class. Notice, it is different than __construct() which I use in regular classes.
Each class is in own file, so I lazy load that file on first use of class. This gives me event of first use of class.
spl_autoload_register(function($class) {
include_once './' . $class . '.php';
if (method_exists($class, 'construct')) {
$class::construct();
}
});
I define class properties as array in a static method and call them via the method. I'm not sure if it's the best solution or not but works great.
Example:
class Foo
{
private static construct_method()
{
return [
'one' => 1,
'two' => 2
];
}
public static any_method()
{
return self::construct_method()['one'] + self::construct_method()['two'];
}
}
echo Foo::any_method(); // 3

PHP PDO: Do the fetch styles FETCH_CLASS and FETCH_INTO fetch into private object properties?

Pretty short question, here is an example:
$prepared = $this->pdo->prepare("SELECT * FROM Users WHERE ID = :ID");
$statement = $prepared->execute(array(":ID" => $User_ID))
$result = $statement->fetchAll(PDO::FETCH_CLASS, "User");
//OR
$User = new User();
$result = $statement->fetch(PDO::FETCH_INTO, $User);
(written from top of the head, could contain syntax errors)
Do those two directly fetch into the private properties of said objects?
I read it also circumvents the __construct function, so will it circumvent private status too?
Very short answer: Yes it will.
class Foo
{
private $id;
public function echoID()
{
echo $this->id;
}
}
$result = $statement->fetchAll(PDO::FETCH_CLASS, "Foo");
$result[0]->echoID(); // your ID
Aside:
This will cause syntax errors $statement->fetchAll(PDO::FETCH_INTO, $User);. You can't use FETCH_INTO with the fetchAll method.
But event with PDO::FETCH_CLASS there is a problem for private properties for subclasses.
E.g.
class Animal
{
private $color;
public function getColor()
{
return $this->color;
}
}
class Cat extends Animal
{
}
$statement->setFetchMode(PDO::FETCH_CLASS, "Cat" );
$someCat = $statement->fetch();
echo $someCat->getColor(); //empty
print_r( $someCat );
/*
now have strange output like:
[color:Animal:private] =>
[color] => grey
*/
But if you set the property to protected - it works fine
The reason you can't access private properties on a super class is because those properties are out of scope. Subclasses don't take on the private attributes of their parent classes, including variables and functions.
edit: Thanks for clarifying your question but it does make my answer look a bit ridiculous here. :p
You could try:
class Foo {
private $id;
public function __set($prop, $val) {
$this->$prop = $val;
}
public function __get($prop) {
return $this->$prop;
}
}
$result = $statement->fetchAll(PDO::FETCH_CLASS, "Foo");
$result[0]->id();

Categories