PDA

View Full Version : Accessing a variable in a function from the main script



keyboard
05-15-2013, 10:12 AM
G'day all!

Say I've got this function that connects to the mysql database -


function sqli_connect($username, $password) {
$connection = mysqli_connect("localhost", $username, $password);
//Test connection to database
if(mysqli_connect_errno()) {
echo "Installation error: Could not connect to database.";
exit;
}
}


Then I call it from here -


<?php
sqli_connect('****', '****');
//Create the databases
if(mysqli_query($connection,"CREATE DATABASE my_db")) { //Executes mysqli query and tests for a return of true at the same time
echo "Database my_db created successfully";
} else {
echo "Error creating database: " . mysqli_error($con);
}
?>


How can I give it the connection variable from the function?
Thanks all :)
keebs

djr33
05-15-2013, 10:15 AM
Don't use a function like that. I usually use an include for setting up a database connection.

Or make it a global variable within the function:
function sqli_connect($username, $password) {
$GLOBALS['connection'] = mysqli_connect("localhost", $username, $password);
//Test connection to database
if(mysqli_connect_errno()) {
echo "Installation error: Could not connect to database.";
exit;
}
}

keyboard
05-15-2013, 10:26 AM
I'm using a function because the user inputs the mysql login details (don't ask :p) so it's a lot easier to just put that stuff into some parameters then using an include (or a require).

Thanks for the globals bit, I'll try that out :)

djr33
05-15-2013, 10:31 AM
Technically there's no reason you couldn't still use an include-- it can be effectively like a function, if you pre-set certain variables before the include. But the globals method will work.

keyboard
05-15-2013, 11:23 AM
Something really weird is going on o.O



<?php
function sqli_connect($username, $password) {
$sqli_connection = mysqli_connect('localhost', $username, $password);
if(!$sqli_connection) {
return 'false'; //Could not connect, return false.
} else {
return 'true'; //Connection fine, return true.
}
}
?>


(for the moment I pulled out the globals bit)

If the connection is valid, it returns true.
If I put in an empty password, no matter the username, I get a true return though.. no clue why. But it's not a valid connection because I ran an sql command and nothing happened.
If I put in an invalid username and a password that isn't empty, or I put in the right username and a password that is wrong (and not empty) I get a php error, it doesn't return false..

So two questions -
1. Any clue why this is happening?
2. How can I stop the php error for just this event?


EDIT -
Actually, just figured out how to stop the php error.. just used an @ on the mysql connect.

traq
05-16-2013, 04:57 AM
Something really weird is going on o.O



<?php
function sqli_connect($username, $password) {
$sqli_connection = mysqli_connect('localhost', $username, $password);
if(!$sqli_connection) {
return 'false'; //Could not connect, return false.
} else {
return 'true'; //Connection fine, return true.
}
}
?>


(for the moment I pulled out the globals bit)

If the connection is valid, it returns true.
If I put in an empty password, no matter the username, I get a true return though.. no clue why. But it's not a valid connection because I ran an sql command and nothing happened.
If I put in an invalid username and a password that isn't empty, or I put in the right username and a password that is wrong (and not empty) I get a php error, it doesn't return false..

So two questions -
1. Any clue why this is happening?
2. How can I stop the php error for just this event?

1. Is there a reason you're returning true/false as strings? :)

2. What is the php error you're getting?



EDIT -
Actually, just figured out how to stop the php error.. just used an @ on the mysql connect.
ugh, please don't do that.

There are some valid uses for the error suppression operator ( @ ), but this isn't one of them.
This is like putting a fancy rug over the spot where the dog barfed so you don't have to clean it up.

NOW, to your original question:

Say I've got this function that connects to the mysql database -


function sqli_connect($username, $password) {
$connection = mysqli_connect("localhost", $username, $password);
//Test connection to database
if(mysqli_connect_errno()) {
echo "Installation error: Could not connect to database.";
exit;
}
}


Then I call it from here -


<?php
sqli_connect('****', '****');
//Create the databases
if(mysqli_query($connection,"CREATE DATABASE my_db")) { //Executes mysqli query and tests for a return of true at the same time
echo "Database my_db created successfully";
} else {
echo "Error creating database: " . mysqli_error($con);
}
?>


How can I give it the connection variable from the function?
Thanks all :)
keebs

Two methods pop to mind. #1 (preferred): return the connection from the function.
<?php

function sqli_connect($username, $password) {
$connection = mysqli_connect("localhost", $username, $password);
//Test connection to database
if(mysqli_connect_errno()) {
return false; // connection failed
}
return $connection; // connection successful
}

// $link will be a mysqli connection on success; or FALSE on failure.
$link = sqli_connect( 'username','password' );

#2: If the function *must* return true/false for some reason, you can pass a var for the connection by reference.
<?php

function sqli_connect( $username,$password,$link=null ) {
$link = mysqli_connect("localhost", $username, $password);
//Test connection to database
if(mysqli_connect_errno()) {
return false; // connection failed
}
return true; // connection successful
}

// $link will be a mysqli connection on success; or FALSE on failure.
// $success will be TRUE on success; or FALSE on failure.
$success = sqli_connect( 'username','password',$link );

I don't recommend using $_GLOBALS, for various reasons.

keyboard
05-16-2013, 07:21 AM
1. Is there a reason you're returning true/false as strings? :)

I was just using that while debugging so I could see which it was returning easier (personal preference)



2. What is the php error you're getting?

The wrong username/password error. -


Warning: mysqli_connect() [<a href='function.mysqli-connect'>function.mysqli-connect</a>]: (28000/1045): Access denied for user 'test'@'localhost' (using password: YES) in C:\wamp\www\****\connect_mysql.php on line 3




ugh, please don't do that.

There are some valid uses for the error suppression operator ( @ ), but this isn't one of them.
This is like putting a fancy rug over the spot where the dog barfed so you don't have to clean it up.

Hahahhaa, I'd just like to stop the PHP error and display my own cleaner one.


NOW, to your original question:

Two methods pop to mind. #1 (preferred): return the connection from the function.
<?php

function sqli_connect($username, $password) {
$connection = mysqli_connect("localhost", $username, $password);
//Test connection to database
if(mysqli_connect_errno()) {
return false; // connection failed
}
return $connection; // connection successful
}

// $link will be a mysqli connection on success; or FALSE on failure.
$link = sqli_connect( 'username','password' );


Doesn't that mean that everytime you want to access the connection, you have to make a new connection? Or would you assign it to a variable?



#2: If the function *must* return true/false for some reason, you can pass a var for the connection by reference.
<?php

function sqli_connect( $username,$password,&$link=null ) {
$link = mysqli_connect("localhost", $username, $password);
//Test connection to database
if(mysqli_connect_errno()) {
return false; // connection failed
}
return true; // connection successful
}

// $link will be a mysqli connection on success; or FALSE on failure.
// $success will be TRUE on success; or FALSE on failure.
$success = sqli_connect( 'username','password',$link );

I don't recommend using $GLOBALS, for various reasons.
Really have no clue what you mean :\

djr33
05-16-2013, 08:19 AM
ugh, please don't do that.

There are some valid uses for the error suppression operator ( @ ), but this isn't one of them.
This is like putting a fancy rug over the spot where the dog barfed so you don't have to clean it up.Hahahhaa, I'd just like to stop the PHP error and display my own cleaner one.I think I agree in this case-- usually error suppression is bad, but your code is not bad-- your account (user/pass) is incorrect, and you won't know what the user has entered. Now, do you actually want to make that possible? It sounds a little dangerous to me. But that's a separate issue. If you expect to potentially get back into from the client, then it's reasonable to suppress errors that generates as long as you handle everything cleanly after that (such as not continuing with the rest of the script!).


---
Traq:


#2: If the function *must* return true/false for some reason, you can pass a var for the connection by reference.

[...code...]I'm not seeing anything special in your code. Is this due to having an undefined variable in the function call? I haven't used this method myself, and I think I'm missing something as well.

Additionally, I believe that methods like that (though I don't entirely understand them) vary significantly by PHP version.


I don't recommend using $_GLOBALS, for various reasons.
I have three responses here:
1. It's $GLOBALS, with no underscore. I still probably make that mistake myself most times I type it, but it's important to remind yourself of that odd difference in spelling (compared to _GET, _POST, etc.).

2. I like using $GLOBALS, although it can cause problems if you might not be in the global scope (a function within a function). Assuming you know you're at the global scope for some reason, I don't see a problem using it-- but it shouldn't be relied upon arbitrarily if you aren't sure. (I like using some global variables such as system settings. If needed, you can create an array and work within that global array, if you're worried about overlapping variable names.)
Note that I do not recommend ever using the global keyword. I strongly prefer $GLOBALS. The reasons are 1) you're overtly using a global variable each time, and 2) it won't accidentally do anything weird to the variable within the function-- you're always referring to $GLOBALS['var'] and intentionally changing it. The potential danger of globals is that you might mess up the global scope within the function's scope. But that danger is much less when overtly using $GLOBALS.

3. This particular case seems like a great example-- you only want one connection per page (right, kb??), so you'd want that to be global (accessible from anywhere), and you wouldn't have any issues of duplicating the variable, etc.
If it happens to be that this might be some kind of function/include with a MySQL connect for a secondary activity-- connecting to an external host for example, so that you can transfer to the local MySQL DB as a backup-- then you would not want global scope. That's where a class would become handy, I think. But I don't know that it's relevant here. Usually, your main MySQL connection should be global, unless you have multiple connections.




---

However, the best answer (better than mine above) is to return the connection as the output. You can also alternatively (with "if") return FALSE as needed, in the event that $link failed for whatever reason. You can also test for TRUE/FALSE based on $link, so you don't need the function itself to return TRUE/FALSE.

traq
05-16-2013, 08:19 PM
Traq:

I'm not seeing anything special in your code. Is this due to having an undefined variable in the function call? I haven't used this method myself, and I think I'm missing something as well.
I made an oversight. function sqli_connect( $username,$password,$link=null ){ ... should be function sqli_connect( $username,$password,&$link=null ){ .... I'm very sorry for the confusion. That & passes the variable $link by reference: instead of copying the value into the function's scope (as normally happens), it literally points at the same value, so anything you do to $link inside the function happens to $link outside the function as well.


1. It's $GLOBALS, with no underscore. I still probably make that mistake myself most times I type it, but it's important to remind yourself of that odd difference in spelling (compared to _GET, _POST, etc.).
Quite right. I corrected that too.


2. I like using $GLOBALS, although it can cause problems if you might not be in the global scope (a function within a function). Assuming you know you're at the global scope for some reason, I don't see a problem using it-- but it shouldn't be relied upon arbitrarily if you aren't sure. (I like using some global variables such as system settings. If needed, you can create an array and work within that global array, if you're worried about overlapping variable names.)
Note that I do not recommend ever using the global keyword. I strongly prefer $GLOBALS. The reasons are 1) you're overtly using a global variable each time, and 2) it won't accidentally do anything weird to the variable within the function-- you're always referring to $GLOBALS['var'] and intentionally changing it. The potential danger of globals is that you might mess up the global scope within the function's scope. But that danger is much less when overtly using $GLOBALS.
Agreed. The potential to confuse scope - function-within-function (or class) - is the main reason I avoid it.



I was just using that while debugging so I could see which it was returning easier (personal preference)
Alright - and sorry, I didn't mean to sound upset in my last post. Had a rough day.

What I was getting at is, since you're returning "true" or "false" (as strings), when you test if( ! $sqli_connection ), it will always evaluate as TRUE. (The string, "false", is boolean TRUE.)



Hahahhaa, I'd just like to stop the PHP error and display my own cleaner one.
That's a good use. I had thought you just wanted to ignore the error.


Doesn't that mean that everytime you want to access the connection, you have to make a new connection? Or would you assign it to a variable?
Assigning it to a variable is what I had in mind. Note the correction I made (&) after Daniel's comment.

keyboard
05-16-2013, 09:34 PM
I made an oversight. function sqli_connect( $username,$password,$link=null ){ ... should be function sqli_connect( $username,$password,&$link=null ){ .... I'm very sorry for the confusion. That & passes the variable $link by reference: instead of copying the value into the function's scope (as normally happens), it literally points at the same value, so anything you do to $link inside the function happens to $link outside the function as well.
That's interesting. It's the & that makes it work like that yes?




Alright - and sorry, I didn't mean to sound upset in my last post. Had a rough day.

What I was getting at is, since you're returning "true" or "false" (as strings), when you test if( ! $sqli_connection ), it will always evaluate as TRUE. (The string, "false", is boolean TRUE.)

At the time, I'd commented out my if in that format, and was just echoing the value of the function. Yeah.



That's a good use. I had thought you just wanted to ignore the error.

Really? I thought you meant what I was doing was a bad thing to be doing.



Assigning it to a variable is what I had in mind. Note the correction I made (&) after Daniel's comment.
[/quote]
Ahhh ok. So I'd just test if it returned false, else assign to variable.. yeah :)


I think I agree in this case-- usually error suppression is bad, but your code is not bad-- your account (user/pass) is incorrect, and you won't know what the user has entered. Now, do you actually want to make that possible? It sounds a little dangerous to me. But that's a separate issue. If you expect to potentially get back into from the client, then it's reasonable to suppress errors that generates as long as you handle everything cleanly after that (such as not continuing with the rest of the script!).
I'm not quite sure what you're getting at there.

traq
05-16-2013, 10:51 PM
That's interesting. It's the & that makes it work like that yes?
Yes.


References in PHP (http://php.net/references) are a means to access the same variable content by different names ...Note that in PHP, variable name and variable content are different, so the same content can have different names.



That's a good use. I had thought you just wanted to ignore the error.

Really? I thought you meant what I was doing was a bad thing to be doing.
Originally, I did think that, but then you explained that you simply want to handle the error yourself, in a different way than PHP does. That's a perfectly appropriate reason to use @.
By and large, @ is simply used to hide errors, which is not a good idea.

djr33
05-16-2013, 11:48 PM
I made an oversight. function sqli_connect( $username,$password,$link=null ){ ... should be function sqli_connect( $username,$password,&$link=null ){ .... I'm very sorry for the confusion. That & passes the variable $link by reference: instead of copying the value into the function's scope (as normally happens), it literally points at the same value, so anything you do to $link inside the function happens to $link outside the function as well.Ah, now that makes sense. I thought I was missing something before. This still isn't something I do often, but it would work. I'd note that I do think this varies by PHP version (even 4 vs. 5 vs. 6, I think they behave differently in subtle ways, but I can't recall for sure).
Can you, as in your example, create a variable at the same time as using it by reference in a function? Or does it need to already exist in the current scope before you do that?


Agreed. The potential to confuse scope - function-within-function (or class) - is the main reason I avoid it.Definitely. But I don't mind too much when I know I'm explicitly referring to truly global things (like system settings). I never use it to "refer to the thing I was just working with outside the function" because it might be within another non-global scope, true.
[Well, maybe not never-- for a lazy/simple script with only one level of functions or just to try out some code, I might do that. But I avoid it in anything complicated/important.]




Just for convenience, because these threads are related, I'll add a link here in case we want to refer back to both in a while (or for anyone who comes across this in the future):
http://www.dynamicdrive.com/forums/showthread.php?73883-When-should-error-suppression-be-used

traq
05-17-2013, 12:06 AM
Can you, as in your example, create a variable at the same time as using it by reference in a function? Or does it need to already exist in the current scope before you do that?
Yes; works just fine. No errors, warnings, nothing.

Also, this should work everywhere (although I never mess around with PHP 4 anymore). Sometime - early in PHP 5, *I think* - something called "call time pass by reference" was deprecated and stopped working. That's when you use & with the argument (or return value) instead of in the function definition:
some_function( $a ){ return $a; }

$arg = 'value';

// bad! doesn't work
some_function( &$arg );

// bad! doesn't work
$return =& some_function( $arg );

reference_function( &$a ){ return &$a; }

// $arg passed in by reference
reference_function( $arg );

// return value assigned by reference
// this is actually *exactly* the same as doing $return = 'value'; but wastes much more time doing it
$return = reference_function( 'value' );
Basically, in recent versions of PHP, you can define functions that accept/return by reference, but you can't force a function to accept/return by reference if it wasn't designed to.

djr33
05-17-2013, 12:39 AM
...something called "call time pass by reference" was deprecated and stopped working. That's when you use & with the argument (or return value) instead of in the function definition:
...
Basically, in recent versions of PHP, you can define functions that accept/return by reference, but you can't force a function to accept/return by reference if it wasn't designed to. Ah, yes. That's exactly what I was thinking of. Ok, so it can't be something you do in the function call, but in the function definition. That means you'll always need to use it like that.