How to create an instance of a class in another class - php

I might be missing something here, I'm not sure. A Google search didn't really help either.
What I'm wanting to do is call the databaseServer class and use its methods within my userControl class. Here is my lib_class.php file:
<?php
include('definitions.php');
class databaseServer {
var $con;
var $db;
var $close;
var $qry;
var $sql;
function connect($host,$user,$pw,$db) {
$this->con = mysql_connect($host,$user,$pw);
if (!$this->con) {
die('Could not connect: ' . mysql_error());
}
else {
echo "Database Connected";
}
$this->selectDb($db);
}
function selectDb($database) {
$this->db = mysql_select_db($database,$this->con);
if (!$this->db) {
echo "Could not Select database";
}
else {
echo "Database Selected";
}
}
function disconnect() {
$this->close = mysql_close($this->con);
if ($this->close) {
echo "Disconnected";
}
}
function query($test) {
if (!mysql_query($test)) {
die("Error: " . mysql_error());
}
}
} // databaseServer
class cookie {
var $expireTime;
function set($name,$value,$expiry) {
$this->expireTime = time()+60*60*24*$expiry;
setcookie($name,$value,$expireTime);
}
function delete($name) {
setcookie($name,"",time()-3600);
}
function check($name) {
if (isset($_COOKIE["$name"]))
echo "Cookie Set";
else
echo "Cookie failed";
}
} //cookie
class userControl {
public function __construct(databaseServer $server) {
$this->server = new databaseServer();
}
function createUser($uname,$pword) {
$this->server->connect(DB_HOST,DB_USER,DB_PASS,DB_NAME);
$result = $this->server->query("SELECT * FROM user_list WHERE uname='" . $this->server->real_escape_string($uname) . "'");
if ($this->result->num_rows() === 0) {
if ($this->server->query("INSERT INTO user_list (uname, pword)
VALUES ('" . $this->server->real_escape_string($uname) . "','" . $this->server->real_escape_string($pword) . "')") {
echo "User Added Successfully!";
}
else {
echo "Error Adding User!";
}
}
else {
echo "User Already Exists!";
}
} // createUser
} // userControl
?>
However, this isn't working and I can't see why. My databaseServer and cookie classes work fine when I omit the userControl class from the file, so I know the error must be in that class somewhere. OOP is something I'm trying to learn and I keep stumbling.
The echoes in the databaseServer class are there only for me to test it. I am implementing the classes in an index.php file as follows:
<?php
include('definitions.php');
include('class_lib.php');
$bmazed = new databaseServer();
$bmazed->connect(DB_HOST,DB_USER,DB_PASS,DB_NAME);
$sql = "INSERT INTO blah
VALUES ('testing 92')";
$bmazed->query($sql);
$bmazed->disconnect();
// $control = new userControl();
// $uname = "Test1";
// $pword = "test1";
// $control->createUser($uname,$pword);
echo "<br />";
echo "<br />";
?>
Lines have been commented out for testing purposes, so I don't have to keep re-writing code.
I really have no idea where the problem lies, I've checked syntax and everything seems fine.

You cannot assign class or instance properties that depend on runtime information when you declare the classes. See the chapter on Class Properties in the PHP Manual.
Change the class to read:
class userControl
{
protected $_server;
public function __construct ()
{
$this->_server = new databaseServer();
}
}
Also, to access class/instance members, you have to to use the $this keyword, e.g.
$this->_server->connect();
On a sidenote, while composition is fine, aggregation is better. It helps your code staying maintainable and loosely coupled, which means it will be much easier to replace components, for instance when writing UnitTests. So consider changing the constructor to use Dependency Injection.

Initialize $server in the constructor:
class userControl {
private $server;
function __construct() {
$this->server = new databaseServer();
}
function createUser($uname,$pword) {
$this->server->connect(DB_HOST,DB_USER,DB_PASS,DB_NAME);
$result = $this->server->query("SELECT * FROM user_list WHERE uname='" . $this->server->real_escape_string($uname) . "'");
if ($this->result->num_rows() === 0) {
if ($this->server->query("INSERT INTO user_list (uname, pword) VALUES ( '" . $this->server->real_escape_string($uname) . "','" . $this->server->real_escape_string($pword) . "')") {
echo "User added Succesfully";
}
else {
echo "Error Adding User";
}
else {
echo "User already exists";
}
}
}

For one, $server won't be accessible from within createUser() because it's in a different scope. PHP scope works a bit differently than one would expect from a C-style language.
Try either passing the $server to createUser(), or initializing the server in createUser(), in which case you should probably have a getServer() function so that you're not initializing it needlessly.
The third option is by far the worst, which is doing "global $server" at the top, inside the function. But it's very bad practice. You have been warned.
Last but not least, you should probably look for COUNT(*) than * in the SQL query, because otherwise you're selecting all the users. :)
If you want further information on PHP's scope, see here (highly recommended):
http://php.net/manual/en/language.variables.scope.php
Hope it helps!

The syntactical stuff certainly was a problem. But even more fundamentally wrong with my code was the fact that the databaseServer->query method doesn't return a value. Making it return a value fixed the problem.
I think, sometimes, it's not possible to see the wood for the trees. :)

Related

How would I go about starting to convert this code into OOP PHP?

I'm trying to learn about Object Oriented Programming and I want to turn this code into such. I've got some knowledge so far from google and here and in particular http://code.tutsplus.com/tutorials/object-oriented-php-for-beginners--net-12762.
The way I understand it is I need classes that contain a certain set of instructions that can be used with universal objects outside of those classes.
My idea so far has been to set up a User class where names are stored (coming from a HTML/PHP form).
class User {
public $nameStore, $fName, $lName, $email;
public function __construct ($fName, $lName, $email) {
$this->$fN = $fName;
$this->$lN = $lName;
$this->$eN = $email;
}
Like the above^. But I'm still confused about where other instructions of my code should go. That's where I need the most help. From what I've read, it hasn't helped me get the full grasp of what I need to do. If someone could help get me started in the right direction on how to make my code into an OOP type I would greatly appreciate it. Thanks!
Below is my procedural code that I want to convert to OOP.
<?php
session_start();
$formNames = $_POST['names'];
$active = (isset($_POST['activate'])) ? $_POST['activate'] : false;
//checks if activate checkbox is being used
$email = '#grantle.com';
$fullnames = explode(", ", $_POST['names']);
if ($active == true) {
$active = '1';
//sets activate checkbox to '1' if it has been selected
}
/*----------------------Function to Insert User-------------------------*/
function newUser($firstName,$lastName,$emailUser,$active,$conn){
//a function to insert a user into a database is here
}
//newUser function enters names in database
/*-------------------------End Function to Insert User--------------------*/
/*-----------------------Function for Errors------------------------------*/
function errorCheck($formNames, $nameSplit, $fullname){
$isValid = false;
if (empty($fullname)) {
$_SESSION['error'][] = '<br><br> Error: Name Missing Here: '.$fullname.'<br><br>';
} elseif (empty($nameSplit[0])) {
$_SESSION['error'][] = '<br><br> Error: First Name Missing Here: '.$fullname.'<br><br>';
} elseif (empty($nameSplit[1])) {
$_SESSION['error'][] = '<br><br> Error: Last Name Missing Here: '.$fullname.'<br><br>';
} elseif (preg_match('/[^A-Za-z, ]/', $fullname)) {
$_SESSION['error'][] = '<br><br> Error: Illegal Character Found in: '.$fullname.'<br><br>';
} else {
$isValid = true;
}
return $isValid;
}
//errorCheck function tests for errors in names and stops them from being entered in the
//database if there are errors in the name. Allows good names to go through
/*-----------------------------End Function for Errors---------------------*/
/*--------------------------Function for Redirect--------------------------*/
function redirect($url){
$string = '<script type="text/javascript">';
$string .= 'window.location = "' .$url. '"';
$string .= '</script>';
echo $string;
}
//redirect function uses a javascript script to redirect user because headers have already been sent.
/*-----------------------------End Function for Redirect-----------------------*/
// Connect to database
I connect to the database here//
// Initialize empty error array
$_SESSION['error'] = array();
foreach ($fullnames as $fullname) {
$nameSplit = explode(" ", $fullname);
//I open the database here
//opens the database
if (errorCheck($formNames, $nameSplit, $fullname)) {
$firstName = $nameSplit[0];//sets first part of name to first name
$lastName = $nameSplit[1];//sets second part of name to last name
$emailUser = $nameSplit[0].$email;//sets first part and adds email extension
newUser($firstName,$lastName,$emailUser,$active,$conn);//do this BELOW only for names that have no errors
}//ends if of errorCheck
}//ends fullnames foreach
if (count($_SESSION['error']) == 0) {
redirect('viewAll.php');
} else {
redirect('form.php');
}
/*Redirects to viewAll page only once and as long as no errors have been found*/
Your
class User {
public $nameStore, $fName, $lName, $email;
public function __construct ($fName, $lName, $email) {
$this->$fN = $fName;
$this->$lN = $lName;
$this->$eN = $email;
}
I would break this up into more specific parts such as GET and SET for each value you are trying to store in the Class:
class User {
private $fName, $lName, $email;
public function set_firstname($fname){
$this->fName = $fname;
}
public function set_surname($lName){
$this->lName = $lName;
}
public function set_email($email){
$this->email = $email;
}
public function get_email(){
return $this->email;
}
public function get_fname(){
return $this->fName;
}
public function get_surname(){
return $this->lName;
}
Then when you create the class, you can add and return each value individually, rather than forcing yourself to do them all at once. This is more flexible. But you can also add the values at the creation of the class as well if you wish, using the __construct similar to what you had already:
public function __construct ($fName = null, $lName = null, $email = null) {
if(!empty($fName)){
$this->set_firstname($fName);
}
if(!empty($lName)){
$this->set_surname($lName);
}
if(filter_var($email, FILTER_VALIDATE_EMAIL) !== false){
$this->set_email($email);
}
}
What this does is for each non-empty value it runs the corresponding SET method. Also checking that the email value is valid before saving it. If no values are passed to the class then it doesn't save anything.
Your setting up of the class is incorrect, firstly you need to include the class file into the working PHP so at the top of your page add:
include "path/to/users.class.php";
And then initiate the class correctly:
$userClassInstance = new User($firstName,$lastName,$emailUser);
When the above line runs, you will then have a User object containing three variables referenced as $userClassInstance. you can do var_dump($userClassInstance);
Be careful as your code has newUser as one line and also has an incorrect number of variables in the construct statement. Generally all the functions in a page should be placed inside an appropriate class, so all your string management functions such as errorCheck() could be put into the Users class to check the values given before assigning them to the variables in the class.
Finally, to view the stored variables you would then do:
print $userClassInstance->get_fname(); //will outout the value of the class $fName

Why is include('../myscript.php') causing an error?

I've been trying to debug my PHP script and I've narrowed down the problem to the line
include "../classes.php";
at the top of my file team_manager.php which is where you see it below.
themes
my_theme
js
management
team_manager.php
project_manager.php
classes.php
footer.php
functions.php
Am I not doing the path correctly? Or could it be something wrong with the contents of classes.php? If it could be a problem with the file being included, below is the file, and let me know if anything immediately stands out as wrong.
<?php
final class MySqlInfo
{
const DBNAME = 'somedb';
const USER = 'someuser';
const PSSWD = 'somepassword';
const TEAMTABLENAME = 'sometablename';
public function getUser ( )
{
return self::USER;
}
public function getPassword ( )
{
return self::PSSWD;
}
}
final class MethodResult
{
public $succeeded;
public $message;
public MethodResult ( $succeededInit = NULL, $messageInit = NULL )
{
this->$succeeded = $succeededInit;
this->$message = $messageInit;
}
}
final class MySite
{
const ROOTURL = 'http://asite.com/subsite';
function getRootUrl()
{
return self::ROOTURL;
}
}
final class TeamManager
{
private $dbcon;
public function TeamManager ( )
{
$dbcon = mysqli_connect('localhost', MySqlInfo.getUser(), MySqlInfo::getPassword());
$dbcon->select_db(MySqlInfo::DBNAME);
// need to add error handling here
}
final public class TeamMember
{
public $name; // team member name
public $title; // team member title
public $bio; // team member bio
public $sord; // team member sort order
public $picfn; // team member profile picture file name
}
public function addMember ( TeamMember $M )
{
if ($this->$dbcon->connect_error)
{
return new MethodResult(false, 'Not connected to database');
}
$q = "INSERT INTO " . MySqlInfo::TEAMTABLENAME . " (" . implode( ',' array($M->name, $M->title, $M->bio, $M->sord, $M->picfn) ) . ") VALUES ('" . implode('\',\'', array($_POST['fullname'], $_POST['title'], $_POST['bio'], $_POST['sord'], $targetFileName)) . "')";
// ^ query for inserting member M to the database
if (!mysqli_query(this->$dbcon, $q))
{
return new MethodResult(false, 'Query to insert new team member failed');
}
return new MethodResult(true, 'Successfully added new member' . $M->name);
}
}
?>
include() might cause an error in case it can't find a file to be included. It's that simple. So you have to make sure that file exists before you include it. Also, never use relative paths like ../script.php, as they introduce a number of issues. And one major issue is that, some hosting providers don't allow relative paths due to security reasons.
So to make sure the file can be included, simply do the check for its existence:
<?php
// dirname(__FILE__) returns an absolute path of the current script
// which is being executed
$file = dirname(__FILE__) . '/script.php';
if (is_file($file)) {
include($file);
} else {
echo 'File does not exist';
}
Also, I see that you write code as an old-school. You might want to take a look at PSR-FIG standards.

Unable To Access PHP Global Variable

I am trying to pull global variable $nsfw but it shows nothing at all. If I echo it inside function, it works. But outside, it fails even when defined as global. Kindly help me out here.
<?php
if(!function_exists('do_example_work'))
{
function do_example_work()
{
global $nsfw;
include("includes/dbconnect.php");
// Create connection
$conn = new mysqli($DBHOST, $DBUSER, $DBPASS, $DBNAME);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
$sql = "SELECT fieldname FROM table WHERE name='$anything'";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
// output data of each row
while($row = $result->fetch_assoc()) {
if ($row["fieldname"] == 1) {
// do somethin
$nsfw = 25;
exit();
} else {
echo "enjoy";
}
}
} else {
echo "0 results";
}
}
echo $nsfw;
};
?>
There are arguments for and against Globals. You can search Stack and the internet and read about:
Globals are bad in many ways, and should be avoided where possible
Globals are not bad, and can be fine/safe to use if you know what you are
doing
The manual:
http://php.net/manual/en/functions.user-defined.php
You seem to be over complicating things with this basic user defined function.
OUT
If you want to get data out of a function, just use the return statement
function do_example_work() {
// Do some stuff here
$nsfw = 25;
return $nsfw; // Return where needed, in conditional statement or end of function
}
// Will echo "25"
echo do_example_work();
IN
FYI:
To get data into the function from outside, just pass the data into your function from the outside as an argument:
function do_example_work($nsfw) {
/** The var "$nsfw" will have whatever data you pass in through the function call
* You can use it as required - check if $nsfw == something
* Or it might be database login details (urgh)
*/
echo $nsfw." - And words from in the function";
}
// Will echo "Pass in argument - And words from in the function"
do_example_work("Pass in argument");
The keyword global in front of a variable name means that the variable is defined somewhere outside the function, and now I want to use that variable. It does not generate a global variable. So you need to define the variable outside the function, and then you can use that variable inside a function using the global keyword in front of it.
In your code I cannot see you defining the variable outside the function. You are just echoing it out at the bottom of your code.
Any specific reason for keeping global variable inside method ?? Move it outside method and it should work for u.
Or
Try GLOBALS as shown below.
function doit() { $GLOBALS['val'] = 'bar'; } doit(); echo $val;
Gives the output as :
bar
Or
<?php
foo();
bar();
function foo() { global $jabberwocky; $jabberwocky="test data<br>"; bar(); } function bar() { global $jabberwocky; echo $jabberwocky; } ?>

The lifecycle of an object in PHP

I have two PHP scripts that I included below. Both of them attempt to do the same thing, but one works and one does not. I'm looking for someone to explain what PHP is doing under the covers. I'm new to PHP and I suspect that my Java experience is poisoning my thought process when I work in PHP.
What I'm attempting to do is functionally very simple -- Insert a question into a mySQL database table, retrieve the primary key of the inserted row, and then insert five answers into another table with a foreign key relationship to the question.
My original logic looked like this:
ManageQuestions.php:
<?php
session_start();
include('query.php');
echo "begin <br>";
if (isset($_POST['submit'])) {
echo "manageQuestion <br>";
$query = new Query;
$query->createTransaction();
$query->executeCreateUpdateDelete("INSERT INTO question (question) VALUES ('".$_POST['question']."'); ");
$question_pid = $query->getLastInsertedId();
$query->commitTransaction(); // Need to figure out how to do dirty reads so I can remove this.
echo $question_pid."<br>";
$result = $query->executeRead("SELECT question_pid FROM question where question_pid = '".$question_pid."';");
echo count($result)."<br>";
//if (count($result) === 1) {
$query->createTransaction(); // Need to figure out how to do dirty reads so I can remove this.
foreach($_POST['answer'] as $answer) {
$correctAnswers = 0;
$query->executeCreateUpdateDelete("INSERT INTO answer (question_fid, answer, isCorrect) VALUES ('".$question_pid."','".$answer['answer']."','".$answer['isCorrect']."')");
if ($answer['isCorrect'] === 1) {
$correctAnswers = $correctAnaswers + 1;
if ($correctAnswers > 1){
echo "Failed to insert answers";
$query->rollBackTransaction();
break;
}
}
}
echo "Success";
$query->commitTransaction();
/* } else {
echo "Failed to insert question";
$query->rollBackTransaction();
} */
}
?>
Query.php:
<?php
session_start();
class Query
{
private $host="<censored>";
private $username="<censored>";
private $password="<censored>";
private $db_name="<censored>";
private $pdo;
private $pdo_statement;
private $pdo_exception;
public function executeCreateUpdateDelete($pQuery)
{
$this->pdo_statement = $this->pdo->prepare($pQuery);
return $this->pdo_statement->execute();
}
public function executeRead($pQuery)
{
try
{
$dbh = new PDO("mysql:host=$this->host;dbname=$this->db_name", $this->username, $this->password);
$result = $dbh->query($pQuery);
$dbh = null;
return $result->fetchAll();
}
catch(PDOException $e)
{
echo $e->getMessage();
}
}
public function createTransaction()
{
$this->pdo = new PDO("mysql:host=$this->host;dbname=$this->db_name", $this->username, $this->password);
$this->pdo->beginTransaction();
}
public function commitTransaction()
{
$this->pdo->commit();
}
public function rollBackTransaction()
{
$this->pdo->rollBack();
}
public function getLastInsertedId()
{
$this->pdo->lastInsertId();
}
}
?>
When I rewrote my logic to not use a separate query class, I was able to do what I wanted to do. The only thing I've been able to find online about the life cycle of a PHP object is that it begins at the start of a script and ends at the end of a script. Does that imply that my query object is instantiated every time I call one of its methods and garbage collected when that particular method ends? Moving the logic out of that class and into the script caused my logic to work. This is what it looks like now:
ManageQuestions.php:
<?php
session_start();
include('query.php');
echo "Begin <br>";
if (isset($_POST['submit'])) {
echo "manageQuestion <br>";
$host="<censored>";
$username="<censored>";
$password="<censored>";
$db_name="<censored>";
$pdo = new PDO("mysql:host=$host;dbname=$db_name", $username, $password);
$stmt = $pdo->prepare("INSERT INTO question (question) VALUES ('".$_POST['question']."'); ");
$stmt->execute();
$question_pid = $pdo->lastInsertId();
echo $question_pid."<br>";
$stmt = $pdo->query("SELECT question_pid FROM question where question_pid = '".$question_pid."';");
$result = $stmt->fetchAll();
echo count($result)."<br>";
foreach($_POST['answer'] as $answer) {
$correctAnswers = 0;
$stmt = $pdo->prepare("INSERT INTO answer (question_fid, answer, isCorrect) VALUES ('".$question_pid."','".$answer['answer']."','".$answer['isCorrect']."')");
$stmt->execute();
}
echo "Success";
}
?>
Even though this fixed my issue, I don't understand why. If someone could explain that, I would be extremely grateful.
Cheers!
Does that imply that my query object is instantiated every time I call one of its methods and garbage collected when that particular method ends?
No. It's per request, not per method call. So the query object is instantiated every time the script is called and it gets unset (and not necessarily garbage collected) when the script ends.
However you could better manage the resource of the PDO object inside your Query class because you create a new instance (which would mean that it connects again to the database server which is not that cheap). So some lazy loading does not seem bad:
class Query
{
...
/** #var PDO */
private $pdo;
...
private function getPdo() {
if (!$this->pdo) {
$this->pdo = new PDO("mysql:host=$this->host;dbname=$this->db_name", $this->username, $this->password);
}
return $this->pdo;
}
public function executeRead($pQuery)
{
try {
$dbh = $this->getPdo();
$result = $dbh->query($pQuery);
return $result->fetchAll();
} catch (PDOException $e) {
echo $e->getMessage();
}
}
public function createTransaction()
{
$this->getPdo()->beginTransaction();
}
...

Php class method not being called

I have a problem with my PHP class, when the user wants to follow another user the follow method is called and when the user wants to stop following the delete_follow is called:
class Follow {
protected static $table_name = "interests";
public function follow() {
global $dbh;
$sql = "INSERT INTO ".self::$table_name." (company_id,user_id,likedate) VALUES (:company_id,:user_id,NOW())";
$follow = $dbh->prepare($sql);
$follow->bindParam(':user_id',$_SESSION['user_id']);
$follow->bindParam(':company_id',$_GET['company']);
if($follow->execute() == true){
header("Location: profile.php?company=".$_GET['company']."");
exit;
} else {
header("Location: error.php");
exit;
}
}
public function delete_follow() {
global $dbh;
$sql = "DELETE FROM ".self::$table_name." WHERE company_id = :company_id AND user_id = :user_id LIMIT 1";
$delete_follow = $dbh->prepare($sql);
$delete_follow->bindParam(':user_id',$_SESSION['user_id']);
$delete_follow->bindParam(':company_id',$_GET['company']);
if($delete_follow->execute() == true) {
header("Location: profile.php?company=".$_GET['company']."");
exit;
} else {
header("Location: error.php");
exit;
}
}
}
My problem is that when the delete_follow method is called it actually calls the follow method I have no idea what is going on.
Here is the code for the follow buttons:
if(isset($_POST['follow'])) {
$follows = new Follow();
$follows->follow();
}
if(isset($_POST['delete_follow'])) {
$follows = new Follow();
$follows->delete_follow();
}
Help please.
The name of your class is Follow. The first method in your class is called follow(). PHP is case insensitive in this aspect and treats that follow() method as the constructor. So this statement--$follows = new Follow()--actually calls the follow() method from your class. Therein could lie your problem.
Read more about PHP constructors here.
I would imagine that there is an error in your form. Perhaps it would be better to have one field follow with a boolean value, say yes or no.

Categories