How to tell if last method in chain? - php

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.

Related

When avoiding nulls in PHP, can I reimplement isset?

I'm running into the problem that I think everyone runs into with null: that is, there are different kinds of null. It could mean "empty", "unchanged", "unset", "unknown", or any number of things. And I am to the point where I need to distinguish between them somehow.
Basically I have a database manager part of my program that receives an object representing data to be updated in the database from from another part of my program that is responsible for validating form data and converting it into said object (Which has one of a several different classes with specific predefined properties). I need some way to distinguish between a "null" property in that object which means "I actually want the value null stored in the database" and a different type of "null" which means "If there is an existing value in the database don't change it". Of the two, the latter is going to be by far the more common case, but I need some way to allow for the former as well.
My current thought, which would seem the best for this situation, is to create a new class which represents each "type" of null, for example an Unchanged class verses a SetToNull type or something like that. Then I could set the property to an instance of one of those classes.
The only issue is that I would like a function that behaves similar to the existing isset() function in that it would allow me to check both if a given property exists and also if it has a real value (as opposed to one of my new null types) in one simple statement.
I'm aware I can do something like this:
if (isset($thing->property) && !($thing->property instanceof Unchanged || $thing->property instanceof SetToNull)){
// do whatever
}
However, that's obviously not ideal because it's long and unwieldy, and I don't want to have that everywhere all over my code base. I'd prefer something like this:
if (myCustomIsset($thing->property)){
// do whatever
}
However, isset doesn't seem to be a normal function; somehow it suppresses warnings if the property hasn't been defined or something like that, so I'm not sure how to implement something like that myself.
Personally, I would not change the model. The model should represent the data in the database, and the values of its properties should be the same as the values of the columns those properties represent.
I would look at changing how the model gets its data. It sounds like you're instantiating the model from the form data, which doesn't include values for every property because the form only updates certain properties.
If you instantiate the model instead by selecting it from the database, and then modify it with the form data before validating and saving it, it will have the correct values for every property, and null will unambiguously mean null.
One thing that comes to mind which I have done in the past is two pass in two arguments. The first argument is the object by itself. The second argument is a string that contains the property name.
Here is an example:
function MyCustomIsset($object, $property) {
return isset($object->$property) && !($object->$property instanceof Unchanged || $object->$property instanceof SetToNull);
}
And here is how you would use it:
if (myCustomIsset($thing, "property")){
// do whatever
}
Since you aren't referencing the property of the object when you pass it in, PHP won't throw an error. In the body of the function, you reference the property using the passed in string argument. You can reference the property using a special feature of PHP called variable variables.

How to pass a boolean argument to a function to act as a switch?

My apologies if the title isn't clear, but I find this difficult to describe. Basically, I have a function that looks for an instance of a class (the school kind) given a class ID number and a date. The function can also create a new class instance if desired.
function get_class_instance($class_id, $date, $create)
Inside the function is a database select on the class_instances table using the class_id and date as arguments. If a matching class_instance is found, its ID is returned. If none is found, there's a conditional for the create argument. If it's true, a new class_instance is created using a database insert and its ID is returned. If false, nothing is changed in the database and false is returned.
I'm still a beginner with PHP and coding generally, so I'm thinking there is probably a better way. The issue is that when calling the function, it might not be clear to someone why there is a boolean being passed.
$original_cinstance_id = get_class_instance($original_class_id, $original_date, 1);
Passing boolean flags to functions to make them do two different things instead of just one is considered a Code Smell in Robert Martin's Clean Code book. The suggested better option would be to have two functions get_whatever and create_whatever.
While a Code Smell depends on context, I think the boolean flag smell does apply in this case, because creating something is different from merely reading it. The former is a Command and the latter is a Query. So they should be separated. One changes state, the other doesn't. It makes for better semantics and separation of concerns to split them. Also, it will reduce the Cyclomatic Complexity of the function by one branch, so you will need one unit-test less to cover it.
Quoting https://martinfowler.com/bliki/FlagArgument.html
Boolean arguments loudly declare that the function does more than one thing. They are confusing and should be eliminated.
Quoting http://www.informit.com/articles/article.aspx?p=1392524
My reasoning here is that the separate methods communicate more clearly what my intention is when I make the call. Instead of having to remember the meaning of the flag variable when I see book(martin, false) I can easily read regularBook(martin).
Additional discussion and reading material:
https://softwareengineering.stackexchange.com/questions/147977/is-it-wrong-to-use-a-boolean-parameter-to-determine-behavior
https://medium.com/#amlcurran/clean-code-the-curse-of-a-boolean-parameter-c237a830b7a3
https://8thlight.com/blog/dariusz-pasciak/2015/05/28/alternatives-to-boolean-parameters.html
You can use a default value for create, so if you pass anything to it, it acts as a normal "get" operation for the database. Like this:
function get_class_instance($class_id, $date, $create = false);
You can query your ID's like this:
$class_id = get_class_instance(1, "18-10-2017");
You can then pass "true" to it whenever you need to create it on the database:
$class_id = get_class_instance(1, "18-10-2017", true);
Instead of passing a number value, you can pass a real boolean value like this:
$original_cinstance_id = get_class_instance($original_class_id, $original_date, true);
Also in the declaration of your function, you can specify a default value to avoid to pass the boolean each time:
function get_class_instance($class_id, $date, $create = false)
one option is to create an enumerator like so:
abstract class create_options {
const no_action = 0;
const create = 1;
}
so now your function call would look like this:
$original_cinstance_id = get_class_instance($original_class_id, $original_date, create_options::no_action);
in practice as long as your code is well commented then this isn't a major issue with boolean flags, but if you had a dozen possible options with different results then this could be useful.
As others have mentioned, in many languages you can also make an argument optional, and have a default behavior unless the caller specifically defines that argument.

Problems with converting mysql over to mysqli errors with mysqli_query & mysqli_fetch_row

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/

One lined class functions, do or don't?

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.

Database class in PHP; only has one function - question about practices and whether it's a good idea

So I have this database class in PHP and I only have 1 function in it (other than __construct and __destruct. Let me explain further...
I had originally written it so when I connected to a database I would just call my function connect_to_db() which returned a mysqli object. I then used this objects functions (->query(), ->prepare(), ->bind_param(), et cetera..) to do whatever. This cluttered (and still is as I haven't switched my code over to my new class yet) with a lot of functions that just do specific things, for example:
function get_country_info($db, $usrid) {
$statement = "select `name`, `population`, `money`, `food` from `countries` where `usr_id` = ?";
$qry = $db->prepare($statement) or
trigger_error("get_country_info():statement failed...");
$qry->bind_param("i", $usrid);
$qry->execute();
$qry->bind_result($name, $population, $money, $food);
$qry->fetch();
$res = array("name" => $name,
"pop" => $population,
"money" => $money,
"food" => $food);
return $res;
}
And what I originally planned to do was just to throw these into a class for clarity, but what I actually ended up doing was creating a class that when created creates a mysqli object for a specific database (supplied via an argument) and when destroyed closes off this link. I very much like not having to worry about typing $db->close(); as when the script finishes executing the connection is closed.
It only has 1 other function; query(). This function can handle any query put forth and outputs it as a multidimensional array. It uses eval(). From what I understand this is generally frowned upon - but eval() is so useful; so why is it frowned upon?
I guess the function may be slow, but seen as I'm just using it for a pet project (browser based country management game) and I haven't noticed anything I'm not worried about that at all. What I am worried about is whether people would generally do this in the 'real world' or whether there is some sort of standard by which people do this, or perhaps something included (or add-on-able) in PHP which is usually used?
I'm self taught, so sometimes I don't really know the best way to go about doing things. Perhaps somebody could advise me here?
The function in question can be seen here: http://pastebin.org/353721, as its ~60 lines and I don't want to clutter the page. I also haven't extensively tested it (I don't even know what unit tests are, so I test by using the function in a lot of different ways) so it may have problems I'm not aware of that you guys can point out.
Thanks.
Doesn't seem to me too bad. You have basically done a really basic wrapper around the database, and you performed the very first step in database independence, which is good.
This can be good for small and well organized projects, but once you will start going more complicated, you will soon notice that your approach has one large disadvantage: you still have your SQL queries split around the site. The day you will change anything in the database, you'll need to go through all your site and look for all the SQL statements: this is bad (I had to do it once...).
You should now move all the SQL code to one place. So there are various options. In a similar context, I made the query() method protected, then made the Db class "abstract" and subclassed it. Each subclass is a class which contains several methods relative to a specific set of tables, and this is the only place where you find SQL. All the rest of the project can only call these methods.
Or, even better, you could use an ORM (oblect relational mapper) which would map each table to an object.
For what concerns the evils of evals: I never used them. But I thought I wasn't going to use a "goto" because it's evil, and then I found the magic place where that was the perfect fit. So, if you have investigated all the possibilities, and you think that's the optimal solution... use it.
Instead of eval, you can use call_user_func() or call_user_func_array().
You should check the return value of execute().
Your function does not support subselects which contain multiple comma's, but only return one value.
You can use trim() instead of ltrim(rtrim()).
I would still use a function like get_country_info() on top of this db class. Often, you want to do something with the data before your application can use it. More importantly, you want to abstract the data storage from your application. That is, the method which uses the country info does not need to know that it came from the database.
As Techpriester wrote: brake it down into smaller parts.
I recommend at least:
the argument to bind converter
the single and multi param bind if-else branch
the sql statement parser (find out about returned fields)
One other approach to your problem would be to build the sql statement inside your query class (arguments would be field names, the table, the where constraints,... ) and to develop subclasses for different query types. This would elimiate the need to parse the statement.
Above this layer you would put a bunch of DAO classes to do the actual work.
But wait: others have done this... (maybe a lot of others to be specific). So using PDO, Doctrine, Propel or even a bigger library like ZendFramework (active record pattern there...) would be the most valuable and stable option.
If you, however, want to learn something about software architecture and OO Systems. Go ahead and build your own, if you do it well you can switch to another DB Layer as soon as your system grows (Version 2.x :-) ).
First: The eval() in your function doesn't serve any purpose as I see it. Why don't you call the $qry->... things directly?
Second, your function is way to complex. Brake it down into smaller parts that call each other.
Third: Manipulating SQL Statements is generally a very bad idea. It's error prone as soon as you feed your function with something like nested statements or other more complicated SQL code. So just don't do it.
Fourth: I wouldn't recommend using mysqli anymore. You should switch to PDO.
As I understand it, your function tries to find out, what fields were in the SELECT clause of the query to build the result array. That is only necessary if you want to allow your database layer it to execute arbitrary queries which is also not a good idea.
When I have to use classic SQL in an application, I predefine every query that I need in some method or function. That function then will know exactly what field it has to read from the result set. So there's no need to parse the SQL code. However, mostly I try to avoid SQL by using things like Doctrine ORM. SQL is just too prone to errors...
About eval(): It is entirely and absolutely evil for several reasons:
It may open the door to code injection.
It makes code unreadable to humans and unparsable to an IDE
It's nearly impossible to debug code that uses eval()
Not really a problem of eval() itself, but when you have to use it, that's a sign of a flawed design.
To your question - you need some experience to learn why there are "best practices", why eval() is deprecated, why people use prepared statements etc.
I'd recommend you to have a look at http://dibiphp.com/cs/ for a nice and concise DB layer for PHP.
You could also try Java when you get some clue about web technologies.
Then you can use cool things like iBatis, which almost got it to PHP
I personally once had a lib for DB, which was used like this:
$aasAreas = Array();
$sSQL = "SELECT id, x, y, x2 AS r, popis FROM ".$oFW->GetOption('tables.areas')
." WHERE id_ad=".asq((int)$_GET['id']);
$oRes = $oFW->GetDB()->Select($sSQL);
if(!$oRes || !$oRes->IsOk()){ $sError = $oRes->GetError(); break; }
else while( $a = $oRes->FetchRow() ){
$aasAreas[] = $a;
}
[OT] And some ORM for PHP attempt, used like this:
// Load by ID
echo "<h3>Load by ID</h3>";
$iID = 1;
echo "<pre>\$oObject = \$oOP->LoadObjectById(".$oClass->GetName().", $iID);</pre>";
$oUser = $oOP->LoadObjectById($oClass, $iID);
echo "<pre>oUser: [".gettype($oUser)."]".AdjustedPrintR($oUser)."</pre>";
echo "<div>GetPoolCount(): ".$oOP->GetPoolCount()."</div>";
// Save
echo "<h3>Save</h3>";
$oUser = new cObjectPersistenceTestClass_User();
$oUser->SetId(1);
$oUser->SetProperty('user', 'as'.rand());
$oUser->SetProperty('pass', 'as');
$oUser->SetProperty('fname', 'Astar');
$oUser->SetProperty('lname', 'Seran');
echo "<pre>oUser: [".gettype($oUser)."]".AdjustedPrintR($oUser)."</pre>";
$bSucc = $oOP->SaveObject($oUser);
echo "<div>".($bSucc ? 'saved' : 'error')."</div>";
// Load by value - load object created above -> Object Pool hit
$xVal = $oUser->GetProperty('user');
$aoUsers = $oOP->LoadObjectsByValue($oClass, 'user', $xVal);
echo "<pre>\$aoUsers: [".gettype($aoUsers)."]".AdjustedPrintR($aoUsers)."</pre>";
etc.

Categories