Basic php class problem - php

Bear with me cos I'm new to oop!
Is it possible to assign the result of a function to an attribute?
This probably doesn't make sense so here's what I think the code might look like!
Class b extends a
{
public $conn= $this->connect();
public function operation() { ...}
}
connect() is a function from class a that connects to a database and returns $result if successful.

Yes that is possible but you need to do that in a method like the constructor:
Class b extends a {
public $conn;
public function __construct() {
$this->conn = $this->connect();
}
public function operation() { /* ... */ }
}

You need to put the call to connect within a method, and then call the method once you've instantiated the class to initialize the connection - or use the constructor method to do so automatically.

Generally, this is bad form, as you cannot be certain what implementation of the connect() method will be called. Is it the one from the current class or the one from the superclass? In fact, I would be surprised if PHP even allowed this.
Initialisation should be done in the constructor, but even then it depends on what the initialisation involves. If it requires calling another method, then the same issue as above exists: which version of the method to call?
However, for the scenario you describe, I would neither initialise the member variable at declaration, nor from within a constructor. Instead, I would pass $conn to the constructor. This is the basis of dependency-injection.

i usually do something like this
$link = mysql_connect(.....,......,......);
Class b extends a {
public $conn;
public function __construct($link) {
$this->conn = $link;
}
public function operation() { /* ... */ }
}
$a = new b($link);
then if your connection details change you change them in one place and if you need to connect to a different server you can and pass in the other link variable.
Another tip for oop database integration is always have a DBable base class to do your basic save() load() find() count() etc, much quicker to work with db savable objects
BaseDBClass
A
B
C
D
X
Y
Z

Related

Why does this come up as non-object?

I am trying to create a really simple database connection class in PHP, but I ran into a bit of problem.
First off, here's the code I wrote:
class db {
protected $db;
public function __construct() {
$this->db = new PDO('mysql:host=127.0.0.1;dbname=main', 'root', '');
}
}
Whenever I try to call $db from another class that extends my database class, I get an error like this one:
Fatal error: Call to a member function prepare() on a non-object in class.php
I call the database link in the other class like the following example:
class example extends db {
public function challenge_exists($challenge) {
$query = $this->db->prepare('SELECT * FROM challenges WHERE challenge = :challenge');
$query->bindParam(':challenge', $challenge, PDO::PARAM_STR);
$query->execute();
if($query->rowCount() > 0) {
return true;
}
}
}
I have no idea what I have done wrong and would appreciate any suggestions on how to make this work.
To the question, if there is a __construct() method in the child class then you need to call the __construct() of the parent class explicitly, or else it is not executed and $db is never instantiated. Though you don't show the child constructor in your example code it is safe to assume that there is one based on the behavior, so:
class example extends db {
public function __construct() {
parent::__construct();
//more stuff
}
}
If you don't need a constructor in the child class then remove it and the parent constructor will be called when you instantiate an object of the child class.
As for the design, this is bad and you should consider one database object and inject that into objects that need it or similar approach:
class example {
public function __construct($db) {
$this->db = $db;
}
}
$db = new db(); // do this once
$example = new example($db); // inject when needed
You should never extend an applications class from a database class in the first place.
User is not a database. It's a user. They have nothing in common. Database have to be used as a service by a user, not being a parent.
Not to mention that creating a hundred connections from the same script is a very bad idea.
Regarding the "accepted" answer, it's just wrong. As long as there is no constructor in the child class defined (like in the OP), then parent counstructor is used. Welcome to Stack Overfraud.

Class Constructor Interfering With Another Class

Essentially, I am just creating two classes where one class, in this case class A, runs a function in another class, in this case class B, to grab some information from the database.
However, when the B_runtime() actually calls upon the database I get the error Cannot access protected property A::$db.
What I don't understand is that even though I have two __construct's in both classes the PDO statement is being very persistent on using the database connection from class A.
I am sure this has something to do with the fact that I am running the B_runtime() from within class A because this doesn't happen if I call it from outside of class A.
I know that I can simply change the protected $db; in class A to a public variable, however, I am really curious as to how I can fix this.
ob_start();
include('/config.php');
ob_end_clean();
$A = new A($db);
$B = new B($db);
echo $A->A_runtime();
class A{
protected $db;
public function __construct($db){
$this->db = $db;
}
public function A_runtime(){
return B::B_runtime();
}
}
class B{
protected $db;
public function __construct($db){
$this->db = $db;
}
public function B_runtime(){
$preparedStatement = $this->db->prepare('SELECT * FROM z_mod_html WHERE ModuleLink = :moduleid LIMIT 1');
$preparedStatement->execute(array(':moduleid' => '1'));
$rows = $preparedStatement->fetchAll();
return $rows[0]['HTML'];
}
}
Sorry for the long amount of code - if anyone has any ideas or suggestions it would be greatly appreciated. Thanks.
You could pass the instance of B to the method. This way you also define the dependancy of your method on class B.
$A = new A($db);
$B = new B($db);
echo $A->A_runtime($B);
class A{
//...
public function A_runtime($instance){
return $instance -> B_runtime();
}
}
You can even use type hinting in PHP 5 to signal that you are expecting an instance of class B there:
public function A_runtime(B $instance){
Oy.
first, you are calling a non-static method as a static method.
B::B_runtime();
should only be used in this way if B_runtime were declared as a static method
static public function B_runtime(){
second, your class has an external dependency which is generally considered not good. a class should only rely on what is given to it, not on globals. this is called the dependency inversion principle. if a class is dependent on somthing, you should have to give this dependency to it via an argument, and even better, use type hinting to make sure that the dependency has the methods you expect it to.
public function A_runtime(B $object_b){
To take this a step further, you should also be using abstracts or interfaces for type hinting instead of concrete classes. this way you can switch B out with a different version of B if it ever becomes necessary.
interface BInterface {
public function B_runtime();
}
then
public function A_runtime(BInterface $object_b){
read up on SOLID principles of OO design.
http://en.wikipedia.org/wiki/SOLID_(object-oriented_design)

PHP Singleton extending class

I am new to OOP (PHP) and just met the design pattern - singleton.
I have found a DB class which uses mysqli (singleton class). I have added some custom methods to it (insert_id(), query(), fetch_result(), etc).
Then I created a new class called UserTools and I want to extend the database class to use the methods I've created previously (query(), fetch_result(), etc).
But I get this error:
Fatal error: Call to private Database::__construct() from invalid context in (...)
when I try to create instance of the new class (User Tools).
What should I do? Is it a right structure?
There are several way to achieve what you want.
One would be :
class UserTools {
private $db;
function __construct() {
$this->db = Database::db_connect();
}
function login() { /* ... */}
}
Although it would be better to directly pass the database instance to the constructor like this :
class UserTools {
private $db;
function __construct($db) {
$this->db = $db;
}
function login() { /* ... */}
}
// Usage
$userTools = new UserTools(Database::db_connect());
If you're really lazy you could just modify your database class and make the constructor public :
class Database {
/* ... */
public function __construct(){/* ... */}
/* ... */
}
class UserTools extends Database {/* ... */}
But I really discourage you to use the latter one. It's really bad code and it doesn't make sense in a logical point of view. Your UserTools class use a database instance. It is not a database.
It is my understanding that only protected and public methods and variables are inherited through extension, not private ones. Try changing your methods/variables from private to protected. public ones are visible to all.
For more information, See: PHP Visibility (Manual)
Edit
Understand the Singleton pattern. It is called 'singleton' because only one instance of a class is expected. Because of this, most classes implementing the singleton pattern define the constructor as private to restrict you from creating more than one.
To create an instance of a singleton, most classes define some kind of getInstance static method, which is public. This public method calls the private constructor, which probably sets flags indiciating that the class has been instantiated in order to prevent further attempts to instantiate the class. The getInstance method returns the results of calling the constructor, essentially the instance of the class.
You could write something like
class UserTools extends DB {
....
}
A quick example on inheritance in PHP:
class A {
public $a;
public function set_a($new_a) { $this->a = $new_a; return $this; }
public function get_a() { return $this->a; }
}
class B extends A {
public $b;
public function set_b($new_b) { $this->b = $new_b; return $this; }
public function get_b() { return $this->b; }
}
$objb = new B();
$objb->set_a("Some Value")->get_a(); //Some Value
The singleton pattern in most cases prevents instantiating the Singleton class by defining the constructor as private (ie private function __construct()).
So if you try to instantiate either your custom class or the original one that you're extending you will get the message above. You should either create a different class or define and use your function as static (eg public static function query($sql, $dbconnection)).
See http://php.net/manual/en/language.oop5.patterns.php

Test if a function is run from a static context

I am writing a PHP class and have included a couple static functions for quick access as they are common for use and are simple in function. However they do use an object in them for database access. I will likely be using these static methods from both a static and non-static context throughout my code so I want to be able to test whether the function was called from a static or non-static context so that I can avoid creating a duplicate object if the function was called from a non-static context (this instance object and the one within the function to be used statically). Is there any way that I can test this in the function so that I can use the instance object if the function is called from a non-static context and create it's own object if the function is called from a static context?
Code Example:
class MyClass {
private $db;
function __constuct(){
$this->db = new DBConnect();
}
public static function myFunction(){
if(/* Is static */){
$db = new DBConnect();
} else {
$db =& $this->db;
}
// Do processing with $db, etc.
}
}
When a method is declared as static,
not only is the magic variable $this
unavailable (returns NULL), but it is
impossible to tell if the function was
actually called from a static context.
A backtrace implies that for a static
method, calling $object->method() is
internally translated to
className::method() at run time.
http://php.net/manual/en/language.oop5.static.php
You can check for non-static access only if you do not force the method to be static-only. Leave out the static keyword from the function declaration and test with:
public function myFunction(){
if(!isset($this)) {
(It can still be called as static function, even though you did not declare it as such.)
Bottom line - don't make classes which contain only static functions. It is not OOP, it is just your old procedural code masquerading as oop
If you are executing functions statically, there is no $this, as there is no object.
You will end up making the private $db a static variable too , and use it as self::$db.
That said, i would recommend to drop this pattern and write something like :
class Foobar
{
protected $_connection = null;
public function __construct( DBConnect $db )
{
$this->_connection = $db;
}
public function some_function()
{
$db = $this->_connection;
// Do processing with $db, etc.
}
}
And you use this class like this :
$db = new DBConnection( /* your password , user , host , etc. */);
$stuff = new FooBar( $db );
$stuff->some_function();
$blah = new DifferentClass( $db );
This way you share the same connection with all the classes that require it. And now the class FooBar is not responsible for making connection or has to know your connection details.
Solution 1: Make the $db variable private, and use it via a getter.
Solution 2: Implement a singleton pattern on the dbal side.
Even when calling a static method from an instance (not recommended), you do not have
access to $this, so your class will fatal.
class sns {
public static function moo() {
var_dump($this->fng);
}
public function goo() {
var_dump($this);
}
}
sns::moo();
$_ = new sns;
$_->moo();
$_->goo();
As another poster has indicated from the php manual.
$db however can be defined statically instead so it only needs to be created once regardless of whether the object is an instance or not.

In a PHP5 class, when does a private constructor get called?

Let's say I'm writing a PHP (>= 5.0) class that's meant to be a singleton. All of the docs I've read say to make the class constructor private so the class can't be directly instantiated.
So if I have something like this:
class SillyDB
{
private function __construct()
{
}
public static function getConnection()
{
}
}
Are there any cases where __construct() is called other than if I'm doing a
new SillyDB()
call inside the class itself?
And why am I allowed to instantiate SillyDB from inside itself at all?
__construct() would only be called if you called it from within a method for the class containing the private constructor. So for your Singleton, you might have a method like so:
class DBConnection
{
private static $Connection = null;
public static function getConnection()
{
if(!isset(self::$Connection))
{
self::$Connection = new DBConnection();
}
return self::$Connection;
}
private function __construct()
{
}
}
$dbConnection = DBConnection::getConnection();
The reason you are able/would want to instantiate the class from within itself is so that you can check to make sure that only one instance exists at any given time. This is the whole point of a Singleton, after all. Using a Singleton for a database connection ensures that your application is not making a ton of DB connections at a time.
Edit: Added $, as suggested by #emanuele-del-grande

Categories