I have a html page that calls a php object to get some data back from the database. It works fine, but the script was getting unwieldy so I decided to break some of it out into a bunch of functions.
So I have the following files:
// htdocs/map.php
<?php
include("config.php");
include("rmap.php");
$id = 1;
$gamenumber = getGameNumber($id);
echo $gamenumber;
?>
// htdocs/config.php
<?php
$_PATHS["base"] = dirname(dirname(__FILE__)) . "\\";
$_PATHS["includes"] = $_PATHS["base"] . "includes\\";
ini_set("include_path", "$_PATHS[includes]");
ini_set("display_errors", "1");
error_reporting(E_ALL);
include("prepend.php");
?>
// includes/prepend.php
<?php
include("session.php");
?>
// includes/session.php
<?php
includes("database.php");
class Session {
function Session() {
}
};
$session = new Session;
?>
// includes/database.php
<?php
include("constants.php");
class Database {
var $connection;
function Database() {
$this->connection = mysql_connect(DB_SERVER, DB_USER, DB_PASS) or die(mysql_error());
mysql_select_db(DB_NAME, $this->connection) or die(mysql_error());
}
function query($query) {
return mysql_query($query, $this->connection);
}
};
/* Create database connection */
$database = new Database;
?>
// includes/rmap.php
<?php
function getGameNumber($id) {
$query = "SELECT gamenumber FROM account_data WHERE usernum=$id";
$result = $database->query($query); // line 5
return mysql_result($result, 0);
}
?>
And constants has a bunch of defines in it (DB_USER, etc).
So, map.php includes config.php. That in turn includes prepend.php which includes session.php and that includes database.php. map.php also includes rmap.php which tries to use the database object.
The problem is I get a
Fatal error: Call to a member function on a non-object in
C:\Develop\map\includes\rmap.php on line 5
The usual cause of this is that the $database object isn't created/initialised, but if I add code to show which gets called when (via echo "DB connection created"; and echo "using DB connection";) they are called (or at least displayed) in the correct order.
If I add include("database.php") to rmap.php I get errors about redefining the stuff in constants.php. If I use require_once I get the same errors as before.
What am I doing wrong here?
$database is not in the scope of function GetGameNumber.
The easiest, though not necessarily best, solution is
<?php
function getGameNumber($id) {
global $database; // added this
$query = "SELECT gamenumber FROM account_data WHERE usernum=$id";
$result = $database->query($query); // line 5
return mysql_result($result, 0);
}
?>
global is deemed not perfect because it violates the principles of OOP, and is said to have some impact on performance because a global variable and all its members are added to the function's scope. I don't know how much that really affects performance, though.
If you want to get into the issue, I asked a question on how to organize such things a while back and got some good answers and links.
You need to include
global $database;
at the top of getGameNumber(), since $database is defined outside of getGameNumber itself
Your $database varibleis not accessible from the function's scope automatically. You might need to declare it as global $database; in the function.
Scopes in PHP are explained in the documentation: http://de3.php.net/manual/en/language.variables.scope.php
Please also mind that PHP 4and MySQL3 are out of support for a looooong time and might contain security problems and other unfixed issues.
Related
Im trying to get data from my database and echo it with a variable, but I have a problem with that. When I try to get my variables from different files it shows me this error:
Undefined variable: con in.
Here some codes:
Code from functions.php:
include "authentication.php";
function GetData() {
$id = session_id();
$result3 = mysqli_query($con,"SELECT * FROM accounts where id='$id'");
while($row3 = mysqli_fetch_array($result3));
{
$email=$row3['email'];
$fullname=$row3['fullname'];
$usualname=$row3['usualname'];
$lastname=$row3['lastname'];
}
}
Code from authentication.php:
$DATABASE_HOST = 'localhost';
$DATABASE_USER = '***';
$DATABASE_PASS = '***';
$DATABASE_NAME = '***';
$con = mysqli_connect($DATABASE_HOST, $DATABASE_USER, $DATABASE_PASS, $DATABASE_NAME);
if ( mysqli_connect_errno() ) {
die ('Failed to connect to MySQL: ' . mysqli_connect_error());
}
This also happens when I try to get variables from other files..
Here you get some screenshots of the error from different files and different variables:
Both files are in the same directory called PHPscripts:
This looks like a problem of scoping.
Remember that in PHP, variables in the global scope cannot be accessed from a function. You must explicitly do something like global $con; inside the function GetData() before you try to access $con.
From a system design point of view this isn't the best approach. It will make it hard to keep track of your variables. You won't know who (which part of your script) is accessing that global and you won't know how it is being modified or in what order. This can lead to some bugs that are very difficult to identify.
require_once dirname(__FILE__) . auth.php;
Require_once or require with Unix full path works like a charm. Replace include stroke in your code.
I'm trying to access the same method twice without having to create the object twice. I made this code
<?php
class help{
public $cn;
public function __construct(){
require_once 'connection.php';
$this->cn = $c;// now $ cn brings the DB connection
}
public function executeQuery( $q ){
self::__construct(); /*I added it because according to I was trying to
invoke again the method without creating a
previous object, if I take it off, it marks me as
if there was no $ cn*/
header('Content-Type: application/json');
date_default_timezone_set('America/Mexico_City');
mysqli_set_charset($this->cn, "utf8");
return mysqli_query( $this->cn, $q );
}
}
$h = new help();
$q = "INSERT INTO FOOBAR (foo_id, bar_id) VALUES('foo','bar')";//new record
$r = $h->executeQuery( $q );//I will do something with $r
$q = "SELECT * FROM FOOBAR";//I retrive all records but the query fails
echo $h->executeQuery( json_encode( $q ) );;
?>
Now, the object does not have a constructor, and if it does not pass the self :: __ construct (); Send me that $ cn is not declared.
How do I solve it? Will I have to create two objects?
Thank you
EDIT
This is my connection.
<?php
global $c;
$c = mysqli_connect("localhost","foo","bar","myDB");
if (mysqli_connect_errno()){
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
?>
You're doing a require_once() call, which is your problem. You will not re-include the file the second time it's called, but being that you're not pulling a global variable, whatever was returned from the first include is not available to you the second time around.
If it's okay to include the file multiple times, you can make the require_once a plain require and that will set your variable as you are expecting.
I've hunted for an answer to this, but still can't explain the inconsistency i'm experiencing. Heregoes...
I'm writing a simple CMS in PHP and cannot understand how I can directly reference external variables from one require call but not another
1. Here's my Db_Conn.php script.
<?php
if(!class_exists('Db_Conn')){
class Db_Conn{
var $pdo;
public function __construct(){
$init_array = parse_ini_file('conf.ini');
try{
$this->pdo = new PDO('mysql:host=' . $init_array['host'] . ';dbname=' . $init_array['database'], $init_array['user'], $init_array['password']);
} catch(PDOException $ex){
exit('Database Error!');
}
}
}
$db_conn = new Db_Conn();
}
?>
2. Here's my simplified article_manager script, that requires the previous DB connection script.
<?php
require_once('class-db_conn.php');
if(!class_exists('Article_Manager')){
class Article_Manager{
public function fetch_article($article_id){
global $db_conn;
$query = $db_conn->pdo->prepare("SELECT * FROM articles WHERE article_id = ?");
$query->bindValue(1, $article_id);
$query->execute();
return $query->fetch();
}
}
$article_manager = new Article_Manager();
}
?>
In this script I can only reference the $db_conn variable is via the global keyword. This makes sense and there are plenty of threads about avoiding globals.
But here's my confusion. Here's a third script that requires the article_manager.
<?php
require_once('includes/class-article_manager.php');
if (!isset($_GET['id'])){
//no page set, back to index
header('Location: index.php');
exit();
} else {
$id = $_GET['id'];
$selected_article = $article_manager->fetch_article($id);
//...some code left out
?>
When I require the article_manager script I DONT have to use global. I can simply call the functions of the $article_manager variable without global referencing.
Could someone please tell me what is going on here? Why don't I have to use global in the second example. I realise the use of globals is discouraged, so I was hoping I could use an alternative method to keep my code encapsulated and.
Article_Manager needs to use global because it's calling $db_conn within the fetch_article function which has it's own scope.
In your second example you're just calling $article_manager within an if statement, presumably already in the global / main scope.
The general idea is that when you want to access variables from within a function they either need to be passed in as an argument or, in this case, a global variable.
I will be straight to the point with this. Can't seem to find it anywhere on the internet. Maybe it is not even possible, i dont know. I do really like to use the method "divide and rule", created it myself. Splitting as much files as possible for easy management (small files and such).
But here is my problem:
I have 5 files:
index.php
inc/config.php
inc/Database.class.php
inc/sidebar.php
inc/forms.php
Okay, what i have done is this:
in my config.php file i included the Database.class.php file and created an object.
include 'Database.class.php';
$user = "root";
$pass = "";
$host = "localhost";
$database = "blah blah";
$db = new Database($user, $pass, $host, $database);
$db->connect();
So i included this config.php and sidebar.php in my index.php file.
(shortened the code, but it functions the same)
include 'inc/config.php';
include 'inc/sidebar.php';
In my sidebar i have a form, for users to login.
in sidebar.php i just include forms.php, this is the forms.php:
(I used print_r to debug my file, to see if anything returns and i left out the method loginFormShow because it is very long and not relevant)
function loginFormProcess($user, $pass)
{
$db->select(blah blah some variables);
$res = $db->getResult();
print_r($res);
}
if (!isset($_POST['submit'])) {
loginFormShow();
} else {
if ($_POST['user'] == "")
{
loginFormShow(1);
}
else if ($_POST['pass'] == "")
{
loginFormShow(2);
}
else
{
$user = $_POST['user'];
$pass = $_POST['pass'];
loginFormProcess($user, $pass);
}
}
And thus, what the problem is. When i try to call the function loginFormProcess, it cant use the object $db.
Can i use 1 object for this? Because on the index page i am going to require some other data from the database. Do i need to create an object for the index page and one for the login form?
Is there any other solution?
If i am not clear, i would love to give some more explanation.
Cheers,
Clemenz
The best solution would be to pass the database object to the function's arguments as follows:
function loginFormProcess($user, $pass, Database $db) {
And call it with an appropriate Database object. This is what know as dependency-injection.
Try this:
function loginFormProcess($user, $pass)
{
global $db;
$db->select(blah blah some variables);
$res = $db->getResult();
print_r($res);
}
For reference: http://php.net/manual/en/language.variables.scope.php
You need to declare $db as global.
Try this:
function loginFormProcess($user, $pass)
{
global $db;
$db->select(blah blah some variables);
$res = $db->getResult();
print_r($res);
}
See: http://www.php.net/manual/en/language.variables.scope.php
The variable $db is created as a global variable in your config.php file. This is invisible from inside the loginFormProcess function. A shotcut solution you can use is declaring your intention of using a global variable by adding the statement global $db; as the first statement inside your function
Everything was working fine in my little project, until I decided to clean up a little bit and moved database-related php-files to their own folder. Then things went strange.
I am trying to use two functions here:
function getEntries () {
require_once("mysqliVariables.php");
$mysqli = new mysqli($dbHost, $dbUname, $dbPwd, $dbName);
$sql = "statement...";
$result = $mysqli->query($sql) or die($mysqli->error);
echo $dbHost; // prints host
return $result;
}
function getBiggestMonth () {
require_once("mysqliVariables.php");
$mysqli = new mysqli($dbHost, $dbUname, $dbPwd, $dbName);
echo $dbHost; // prints nothing! why?
$sql = "statement...";
$result = $mysqli->query($sql) or die($mysqli->error); // this line does not run, of course.
return $result;
}
I use another function in a different file (and folder) to call these functions, that starts like this:
function listTasks() {
require_once("db/mysqliFunctions.php");
// Get entries using mysqli.
$tasks = getEntries();
echo "<pre>";
var_dump($tasks);
echo "</pre>"; // program works fine this far.
$bm = getBiggestMonth(); // program breaks somehow during this function call.
My variables are in a php-file like so:
<?php
$dbHost = "host";
$dbUname = "username";
$dbPwd = "password";
$dbName = "databasename";
?>
If I switch the funtion's call order, then getBiggestMonth() runs fine and the other one won't. Also, all of this worked fine when all the files were located in the same folder (the functions were then static functions inside a class, but that shouldn't be an issue, the same problem persists here), so I dont understand how possible variable scope can be different here, and require_once should take care of other things. Help?
This is because you are using require_once. It will only include the configuration once. You can change it to use require so that it will work as you expect.
The require_once() statement is identical to require() except PHP will
check if the file has already been included, and if so, not include
(require) it again.
You are using require_once to pull in a file into the scope of the getEntries() function. PHP keeps a record of the files that have been required in so when you then call require_once in getBiggestMonth() it knows it has already been included in getEntries(). Because it has already been included it does not require the file in again so you don't get your variables in your getBiggestMonth() scope.
require_once does not have anything to do with variables it just monitors the files that have been included into the current PHP process.
The echo statement after the return in getEntries() wont obviously work as the function exits after the return.