Reading this page http://www.php.net/manual/en/mysqli-stmt.bind-result.php
I got some questions about PS
In examples i don't see $stmt = $db->stmt_init(); Is it required to create new instance (
add $stmt=$db->stmt_init() line) at the beginning of the every
statement and $stmt->close at the end or it doesn't matter at all: I
can start from $stmt = $mysqli->prepare("... ??
Can I create statement object 1 time at the beginning of the code and
use it all code long?
As mysqli_prepare() creates an object with the link identifier and the query you want to run, you don't need to use mysqli_stmt::init.
The advantage of using mysqli_stmt::init is to create an instance of the object in a config file for example. Any subsequently required / included scripts will have a query object ready for use, reducing the amount of code you need to write.
Second question: Yes. Think of the object as having a lifecycle from the line of code it is initialised to the last line of code of the script OR when its __destruct() magic method is called. It can be used at anytime once created allowing you to constantly change the query and execute more code with the same object.
As a note: you must always use mysqli_stmt::close after each query (once you have taken the results). This clears the objects query and result sets, re-initialising the object to the same state it would have been in when first created.
Hope that helps.
Related
Is there such a thing like an "executed" flag for PDOStatement (PDOStatement) to see if the statement has been executed (by calling PDOStatement::execute())? Or am I forced to just set my own flag?
Judging by the documentation, there doesn't seem to be a flag (the only documented property is $queryString) - but I thought I'ld still ask before doing it manually. Mainly to distinguish prepared from already executed statements.
Once a statement is prepared, you can execute it multiple times, so maybe the builders didn't think a flag like that would be useful, and personally I'm a bit curious about your use case too.
But it is possible: Using PDOStatement::errorCode, you can get the error code of the last statement. This function will return an exmpty string when the statement is not executed yet, and will be filled with an error code, (or 00000 for no error), after the statement is executed.
No there is not. You can reuse a PDOStatement, which is the use case supported with PDO:prepare.
I've started using method chains in my PHP app:
$object->do()->something();
Specifically with querying databases:
$database->select()->from('mytable');
However at the moment I need to call a function to actually perform the query at the end:
$database->select()->from('mytable')->perform();
This is annoying because usually every chain will perform straight away. Sometimes it wouldn't, but 9 times out of 10 it will. I need this to work with any object, not just a database handler.
Is there a way to tell if the last method I call is the last one in the method itself, so it would perform() without me telling it to?
If not, I might just try to use some keywords like ->now() instead of ->perform()
I have a few idea(s):
each method has a parameter that if set will let it know it's at the end (maybe it can loop through all parameters to find if a special constant was passed?) eg $object->do()->something(now);
In Perl's DBIX::Class they trigger the query upon using the data. So each query chain doesn't return the database object but a DBIX::Class object that wraps around the database table object.
You can possibly try to implement a similar system. So, for example the following:
$resultSet = $database->select()->from('mytable');
does not actually return the table but a resultSet object. And only when you try to do:
$resultSet->next();
will the library actually fetch the data from the database.
Basically, all the accessor methods like first(), last(), all() and next() fetch and cache the data. If the data has already been fetched and is cached in memory then further calls to accessor methods on the resultSet object should just read the hash in memory instead of connecting to the database.
Additional detail:
Inserts don't have complex clauses like select. So the inserting function doesn't need to be chainable. So for inserts, you can simply have the API do something like this:
$database->insert()->into('mytable')->values({
foo => "hello",
bar => "world"
});
where the values() method act as the inserting function and triggers the database query.
Updates can simply be done on the row object. You can have the API do something like this:
$row = $database->select()->from('mytable')->first();
$row->foo('goodbye');
$row->update();
or alternatively:
$row->update({
foo => "goodbye"
});
And have the update() method trigger the database query.
Using an operator overloading extension, you can specify one of the unary operators for prompting executions
Example:
~$db->select()->from()->where();
If you want to avoid installing an extension, one suggestion I can make is using some kind of escape character in your latest chain call to promp the execution. You should omit it from the final query to avoid syntax errors.
Example:
$db->select()->from()->where("id = 1 ~"); //~ character implies automatic execution
Is there a way to tell if the last method I call is the last one in the method itself
No, I believe there is no such thing. That's because "chain calls" do not differ from "one by one calls". That's just a kind of syntactic sugar for "call => return object => call => return object ..." chain.
I have a few idea(s):
- each method has a parameter that if set will let it know it's at the end (maybe it can
loop through all parameters to find if a special constant was passed?) eg
$object->do()->something(now);
You can achieve an effect of an idea you suggested by overloading __call() method. This way you can abstract your parameter checking logic nicely.
But be aware, that such behaviour is not really obvious architecture-wise and you probably should consider PDO-like approach, that is using "finalizing" method like perform() or do() which, I think, you already have.
Here is the edited script without errors. And the 2 fixes applied to it. To those who helped in part, thank you. To mentions that the code is unclear or messy is inconsequential. Given that most of the following is common structure in mysql queries. Even the example documentation for mysql followed this similar flow. Members who reply should negate from pointless internet banter. Its more worth your time, and my own to do so. Those who stayed on topic and assisted, I thank you.
For example:
$row = mysqli_fetch_row(mysqli_query($con, "SELECT test_table.points FROM test_table WHERE test_table.key = '" . $key . "'"));
if ($row[0] > 0){ // exists
Where $row will return a non-zero result if true. Otherwise 0 on false. There is little need to check mysqli_fetch_row and/or mysqli_query. Since checking $row in simplicity works fine. It is unneeded to check mysqli_fetch_row and/or mysqli_query individually in a general exists condition. It does accurately provide exist / does not exist results. There is no $result $row $query just $row.
The noted deviation to that normal flow was my desire to use call_user_func. And to poll in func and params through $_GET. Will be looking more at PDO. However, the clean code before exec should do alright job for now. Which is to clean before exec.
All in all, the code works just as it should. And have since written more to manage a mysql database. From write, write chunk, read, read chunk, delete, delete chunk.
Also to collect numbered records on request. For example say you have 6 records for the same John Smith. You can now collate and scan for differences in those records. Either for what you want, dont want, etc. Or if say you just want to blindly call the first 3 of those records for John Smith.
mysqli_fetch_row & mysqli_fetch_row fix :
FROM Calling $con outside function then into as per mysql. Which in mysqli does not work as expected. There was no error with the functions, over how $con was being handled.
TO Calling $con inside function with just the added global $con. May end up using $GLOBALS even for this.
Result : Calling $con outside function then in works fine in mysql. In mysqli it requires global be set within the function. ie global $con. Or it fails.
call_user_func non-critical error fix :
FROM call_user_func($func($_GET['user'],$_GET['key'],$_GET['points'],$_GET['type']));
TO call_user_func($func,$_GET['user'],$_GET['key'],$_GET['points'],$_GET['type']);
Result : Both lines execute correctly. From executed with a non-critical error. TO does the same thing, but with no following non-critical error.
Sample Output for both : user=MY_Name;key=34342$ee56i1;points=1234;type=
-- code removed as fixes solved the issues --
You are using call_user_func wrong read the manutal
call_user_func first parameter is the callback - in your case it's a function inside your class so it should be something like this:
If you have a non-static function in an object:
class Test{
public function doit($a){
echo($a);
}
}
$t = new Test();
call_user_func(array($t,'doit'),'asfaasfs');
and in static functions inside object:
class Test{
public static function doit($a){
echo($a);
}
}
call_user_func('Test::doit','asfaasfs');
You have a few problems.
$con is declared outside the class, and is thus not available inside the class. You need to pass it into the class (the better option), or specify it as a global (the quick+dirty option).
mysqli_fetch_row(mysqli_query($con,'...'))
This code is obviously converted directly from your old mysql_xx() code, but it's not great.
You're ignoring any possible error condition that is returned by mysqli_query(). This means that if it fails, it'll pass false into the mysqli_fetch_row() function, which will then fail with a meaningless error expects parameter 1 to be mysqli_result, rather than actually telling you what the error was in the query.
The thing is, because of my first point above, with $con not being set, mysqli_query() is failing, and this is why you're getting the error in mysqli_fetch_row().
Ideally, you should split this code out into multiple lines. Call mysqli_query() on its own, then do some error checking, then call mysqli_fetch_row() only once you know that the query actually worked.
Hope that helps explain what the problems are here. Solve those two points, and you should be well on the way to sorting the whole thing out.
Once you've got rid of those fatal errors, you should also take time to work on the problem that your code is vulnerable to SQL injection attacks. You're currently passing your $_GET variables directly into the query strings without any sanitisation. This will make your system very fragile and easy to hack. You should consider using Parameterised Queries, which is a feature of the mysqli library designed to make it easier to deal with variables in SQL queries in a safe and secure way.
Your class is pointless at the moment, perhaps stick to writing imperative style code as it will at least be cleaner.
At the moment, you should pass $con to your MYsql class to use itself as a resource, not try to access it as a global variable.
Your are not filtering your user's input either, this is dangerous and could lead to SQL injection attacks on your site.
I'd encourage you to read through these two articles, and once you grok them, I'd also encourage you to simply switch to using PDO with prepared statements. This will stop SQL injection attacks that your code currently allows.
http://net.tutsplus.com/tutorials/php/pdo-vs-mysqli-which-should-you-use/
http://net.tutsplus.com/tutorials/php/why-you-should-be-using-phps-pdo-for-database-access/
I'm using PDO against MSSQL, and need to run nested queries. They are all prepared statements. If I try to use the fetch() method, it inner queries fail immediately, so I used fetchAll(). So, I get something like this, with Programs, Products and Budgets:
$pgm_stmt->execute();
$pgm_res = $pgm_stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($pgm_res as $pgmrow) {
$prod_stmt->execute(array($pgmrow['ID']));
$prod_res = $prod_stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($prod_res as $prodrow) {
$bdgt_stmt->execute(array($pgmrow['ID'], $prodrow['ID']));
$bdgt_res = $bdgt_stmt->fetchAll(PDO::FETCH_NUM);
foreach ($bdgt_res as $bdgtrow) {
... work here
}
}
}
OK, everything works the first time through, but when it loops back for the 2nd program, the product result set gets corrupted somehow. When I dump the $prod_res variable right after the fetchAll(), the values are randomly assigned from other parts of memory, bits of other arrays, etc. Of course it fails because the $prodrow['ID'] value is undefined, because that whole result set is mangled.
Can someone help me troubleshoot this? I'm stumped.
Thanks.
Not a bug, but a feature, see: https://bugs.php.net/bug.php?id=65945
This is the behavior of MSSQL (TDS), DBLIB and FreeTDS. One statement per connection rule. If you initiate another statement, the previous statement is cancelled.
The previous versions buffered the entire result set in memory leading to OOM errors on large results sets.
The previous behavior can be replicated using fetchAll() and a loop if desired. Another workaround is to open 2 connection objects, one per statement.
Is there any harm to having functions one lined instead of multilined? For example, I wrote a class file for a PDO database connection. All the functions I wrote for it, are one lined. I haven't run into any errors yet, but can they crop up if there is lag or something?
Here are some of the functions.
public function getObject($query, $object) {
return $this->db->prepare("$query")->execute()->fetch(PDO::FETCH_OBJ)->$object;
}
public function getArray($query) {
return $this->db->prepare("$query")->execute()->fetchAll(PDO::FETCH_NUM);
}
public function insertArray($query, $array) {
return $this->db->prepare("$query")->execute($array);
}
Will this eventually run into problems? Or do they get called one section at a time, as if they were on their own line?
Thanks.
Using chained methods in one single line like this
return $this->db->prepare("$query")->execute()->fetch(PDO::FETCH_OBJ)->$object;
is what Robert Martin calls "Train Wrecks" in Clean Code (pg 98/99). It's hard to read and "generally considered sloppy" and should be avoided for the more readable
$statement = $this->db->prepare("$query");
$statement->execute();
$result = $statement->fetch(PDO::FETCH_OBJ);
return $result->$object;
Please note that I corrected the code in the snippet above, as your one-liner will not work, because execute returns a boolean, so you cannot call fetch on it:
bool PDOStatement::execute ([ array $input_parameters ] )
In other words, you cannot write this as a one-line statement anyway.
Also note that Method Chaining is very often a violation of the Law of Demeter, which states that
a method M of an object O may only invoke the methods of the following kinds of objects:
O itself
M's parameters
any objects created/instantiated within M
O's direct component objects
a global variable, accessible by O, in the scope of M
Not following LoD usually leads to Mockfests in your UnitTests and makes your application tightly coupled to much more classes than necessary, which in turn impairs reusability and increases the time required for changes (among other things).
Imperative code will always get called in the expected order. There is nothing to worry about, except maybe if the code is readable or not. In case where the line is very very long, you might want to wrap it to multiple lines, but the examples you show look OK to me.
If the connection to the database fails for some reason it could cause a FATAL_ERROR because one of the objects will return false.