I was reading about how to detect the encoding of a file in PHP, and on some blog or somewhere, it was suggested to do this:
if (function_exists('mb_detect_encoding')) {
function is_utf8($str) {
// do stuff using the mb* libraries
}
} else {
function is_utf8($str) {
// do stuff manually
}
}
To me this feels very messy, and could be replaced with this:
function is_utf8($str) {
if (...) {
// mb stuff here
} else {
// manual stuff here
}
}
However, I can also see that it also has some benefits. Depending how complicated the if statement is, and how often the function is called, this might be much more efficient. My question is this: At what point would you consider splitting a function into two like in the first example? Are there any other pros/cons that I've missed?
Edit: Please don't get hung up on the example here, the question is about this practice in general.
My gut reaction is to go with a single declaration of the is_utf8 function. The PHP engine is mighty good at optimization and the overhead of multiple calls to function_exists() should be negligible.
A good practice, maybe not in that case, but in general might involve the use of OOP (objects) with factory methods.
class my_utf8
{
// A static method that determine what object to create
public static function factory() {
if (function_exists('mb_detect_encoding')) {
return new my_utf8_with_mb;
} else {
return new my_utf8_without_mb;
}
}
}
class my_utf8_with_mb extends my_utf8 {
public function is_utf8($str) {
// do stuff using the mb* libraries
}
}
class my_utf8_without_mb extends my_utf8 {
public function is_utf8($str) {
// do stuff without the mb* libraries
}
}
And in your application :
global $myUtfInstance;
// Call once
$myUtfInstance = my_utf8::factory();
// later and forever...
$myUtfInstance->is_utf8($str);
You could also involve a singleton pattern depending on what you do. It does not skip the IF but eliminate the need of a global variable.
class my_utf8
{
private static $instance;
public static function factory() {
if (function_exists('mb_detect_encoding')) {
return new my_utf8_with_mb;
} else {
return new my_utf8_without_mb;
}
}
public static function getInstance()
{
if (!self::$instance) {
self::$instance = self::factory();
}
return self::$instance;
}
}
And in your code :
my_utf8::getInstance()->is_utf8($str);
Stylistically, I'm inclined to push for the second. If performance is an issue though, you'd do well to consider using the first.
if (function_exists("sin")) {
function baz($farfs) {
print "I am the first baz";
}
} else {
function baz($farfs) {
print "I am the second baz";
}
}
function blarg($fgar) {
if (function_exists("sin")) {
print "I am the first blarg";
} else {
print "I am the second blarg";
}
}
for ($i=0;$i
I ran this on my workstation here, and found that the aggregate time of calls to baz took anywhere from 50-75% of the aggregate calls to blarg, depending on whether the function being tested actually exists.
Here are the actual numbers:
function_exists("foobar")
blarg: 36.64 ms
baz: 14.71 ms
function_exists("sin")
blarg: 35.24 ms
baz: 23.59 ms
The only difference between these two functions is the conditional and the two extra characters in the output. Interestingly enough, the 10001 calls to function_exists only take 0.18 and 0.11 ms respectively on the two tests. I'm wondering if there is some function call overhead not being accounted for in either profile.
As for style though, I really dislike the first. Defining a function by name in two different places seems like a shady thing to do, especially when relying on the oddness in PHP that makes function definitions not performed in global scope affect global scope anyway. On the other hand, my biases just might be showing, and the rest of the PHP community might not have a problem with relying on the PHP interpreter as a sort of preprocessor in this instance.
shrug Such are the matters of style.
By default, go always with the most readable solution. If that particular piece of code turns out to be a significant drag (measured, not assumed) on your application, then you optimize it.
I'll apologize in advance for what's most likely pretty ugly PHP, but I'd do something more like:
if (function_exists('mb_detect_encoding')) {
function is_utf8_mb($str) {
// do stuff using the mb* libraries
}
}
function is_utf8_manual($str) {
// do stuff manually
}
if (function_exists('is_utf8_mb')) {
function is_utf8($str) {
is_utf8_mb($str)
}
} else {
function is_utf8($str) {
is_utf8_manual($str)
}
}
That is: an is_utf8 variant will exist in the execution environment dependent only on if it can work in that environment. Each variant is in a code block of the minimal size needed to determine if that variant should be loaded, and to perform its function. The main reason is that I think the smaller the amount of space you need to write your function, the easier it is for a reader to build an understanding of the function's behavior. Your eyes have to travel less, you have to scroll less, there are generally fewer of those trivial frustrations involved in understanding a function for the first time. The second reason is that it provides a better way of testing your code - you can more easily automate a check that the is_utf8 variant routines are producing the same result when you can access all of them at the same time.
There are two aspects at play here: performance (don't pay for what you don't need), and readability.
As many wise posters say: don't bother about performance until it's proven to be a problem.
But concerning readability, in my opinion, a function should show as little layers of responsibility as possible. Functions that do exactly one thing are easiest understood.
Your question is actually about 'how should I mix two responsibilities':
what: detect the presence of a library, and 'dispatch' to the correct code block
how to use the library vs. how to do without.
That's why I would really create two 'layers': one layer dispatching to the appropriate function, and another layer containing 'code blocks', wrapped in a function with the proper name.
And then you still have the choice whether to do the dispatching explicitly, or to use PHP's possibility to declare functions on-the-fly.
// functionality: defines how to detect utf8 encoding
//
function is_utf8_mb( $arg ) {
... // using the mb library
}
function is_utf8_bare( $arg ) {
... // hand coded
}
// dispatching layer: decide what library to use
//
// option 1: define on-the-fly
function define_utf8_function() {
if( function_exists('mb_detect_encoding') ) {
function is_utf8( $arg ) { return is_utf8_mb( $arg ); }
} else {
function is_utf8( $arg ) { return is_utf8_bare( $arg ); }
}
}
// option 2: check the dispatching on each function call
function is_utf8_runtimedispatch( $arg ) {
if( function_exists('mb_detect_encoding') )
return is_utf8_mb( $arg );
else
return is_utf8_bar( $arg );
}
Related
Trying to achieve method overloading using PHP (don't confuse with overloading definition from PHP manual), is not easy there is clear trade off, because of nature of PHP you have to have one method and if or switch statement inside to provide overloading, it creates procedural code that is difficult to read in long methods.
Is there any advantage of having method overloading in PHP, can it be achieved in any other way?
class MyClass {
public function doMany($input) {
if (is_array($input)) {
...
} else if (is_float($input)) {
...
}
}
}
versus traditional approach
class MyClass {
public function doArray(array $input) {
...
}
public function doFloat(float $input) {
...
}
}
The traditional approach would be:
class Aclass {
public function doStuff(int $a) {
// return other stuff
}
public function doStuff(float $a) {
// return other stuff
}
}
Notice the same function name just different type for the paramaters.
Your first approach is usually the way to go if you want to simulate overloading in php. Generally speaking you don't really need overloading in PHP since it's loosely type and by definition you can't really have overloading.
To answer your question. If you really need to have overloading, then your first approach seems appropriate. Use a switch to make it more readable.
Disclaimer: While you can do that, I don't recommend it. Heck, you can do just about anything if you want to. It doesn't mean you should.
Within the class, I created a set method if what that is called that accepts data.
<?php
public function set_name($name)
{
$this->name = ucwords(trim($name));
// return $this->name;
}
?>
My question is, do I have to return the result of the function or not necessary. If not why? I know in the display() method you have to return like so: return $this->name;. I'm really confused.
You don't have to return anything.
However, it's good practice to return something on certain functions to perform tests on it, even if it's just true or false, to clarify that the function performed correctly.
Given your code, generally, I personally don't set a return on setters. So it's fine not to return anything.
For example, you may want to test that your name only contains letters and return false if it doesn't
<?php
public function set_name($name) {
if(preg_match("/[A-Za-z]+/", $name) {
$this->name = ucwords(trim($name));
return true;
} else {
return false;
}
}
?>
Then you'd call it by:
<?php
if(!set_name($name)) {
echo "There was an error";
}
?>
However, this doesn't comply with mvc framework.
In Object Oriented programming language return the value is the best. Otherwise it will be childish and hard to maintain bugs when your sites grow bigger and it tend to errors prone.
You don't HAVE TO return the result in a setter function, the best use is to make some getter functions to get the datas.
Otherwise my point of view with setter is to return $this. With this little trick you can chain up setter functions.
For exemple :
class C
{
private $arg;
private $arg2;
function setArg($NewArg)
{
// your tests or so
$this->arg = $NewArg;
return $this;
}
function setArg2($NewArg)
{
// your tests or so
$this->arg2 = $NewArg;
return $this;
}
function getArg()
{
return $this->arg;
}
function getArg2()
{
return $this->arg2;
}
}
And you can use it that way :
$Item = new C();
$Item->setArg('hello')
->setArg2('hi');
$Item->getArg(); // return 'hello'
$Item->getArg2(); // return 'hi'
It's more semantic in this case. Do I expect a function called set_name to give me the name? No, not really, that sounds silly. In this case, I wouldn't return anything.
Because a function should only do one thing, you should always be able to reduce the choice to a binary "yes, I'd expect it to return something" or "no, that doesn't make any sense" decision.
Generally speaking your methods should do what somebody would expect them to do just by looking at their names (some people will hate me for saying this).
It's always a good idea to put yourself in the position of a programmer who has to work with your code. If had to use a method called: set_name() he would never expect it to return something.
Your methods always should do what one would expect them to do and complain to the outer environment through exceptions. Not more, not less.
If you put this into practice: Congratulations. You have just built yourself a great and reliable alarm bell for methods that are doing too much (seperation of concerns) and you're a step closer to clean software design.
Of course that's not something you would force come hell or high water (nothing is), but that's something you need to decide by yourself. If you cannot do that for whatever reasons (for example method chaining, which has been mentioned several times) , you could provide a good documentation of your class(es) and make clear what the methods actually do.
For years now I have been writing (on and off) at an office-management app. I need to rewrite it, because the code has become unmaintainable, so I will choose a PHP-framework and rewrite the business logic into classes.
Now I am stuck with this fundamentamental question: do I still need to return the result and if yes, how do I capture that result? Some pseudocode to make my question clear:
function a( $1, $2, $3 ) {
doThis( if ... return TRUE; if ... return FALSE; );
if ( doThis() != TRUE ) { return; }
doThat();
}
vs
class example {
private $1;
private $2;
private $3;
public function go() { $this->doThis(); $this->doThat(); }
private function doThis(){}
private function doThat(){}
}
$a = new example;
$a->go();
How can I stop the execution of the go()-method if the doThis()-method does not perform as expected? I presume I should not go about returning booleans and checking inside every method if a certain property is set to false? Or do I simply throw an Exception if something went wrong and don't do anything if everything is ok?
This is pretty basic, I know...
Thx!
Exceptions are for exceptional behaviour, so don't throw exceptions just because your code isn't in a preferred state. When it comes to writing OOP, some people still manage to write procedural while using a object oriented framework, obviously you'd want to avoid that, a simple rule of thumb is to not write God-objects.
Now what I'm guessing that you want to do is to call two functions that should be called in a specific order, and there are several ways to do this, and it actually boils down to, what kind of class you have. Lets say you have an object of the type Person then you might want to call different methods on that person from somewhere else:
$john = new Person();
$john->tryToWakeUp();
if($john->isAwake) {
$john->brushTeeth();
} else {
echo "John is still sleeping!";
}
On the other hand you might have an object of the type Engine which might want to do several stuff internally for certain actions, like start:
class Engine {
public function start() {
$this->checkFuel();
if($this->hasFuel()) {
try {
$this->initializeSomethingThatHasToDoWithEngineStartUp();
} catch (EngineException $ee) {
$this->engineState = BAD_ENGINE;
Logger::log("Engine did not start");
}
}
}
}
I'd recommend you to read up on object oriented design and play around with it before you try to convert all of your business rules, because It's likely that half way through you'll realize that you've designed everything wrong. Object Oriented Design is not easy, but it does make sense EDIT:( It should make sense ).
I was reading about Object Calisthenics and one of the rules was wrapping primitive types and strings:
class UIComponent {
public function repaint($animate = true)
{
//
}
}
$component->animate(false);
becomes:
class UIComponent {
public function repaint(Animate $animate)
{
//
}
}
class Animate {
private $animate;
public function __construct($animate = true)
{
$this->animate = $animate;
}
}
$component->animate(new Animate(false));
What advantages do I gain with this technique? In my opinion, I think it just complicated things and added more lines of code.
In this case, it is true, that it is a little bit oversized, but there are other examples, where it can make sense
class Identifier {
protected $id;
public function __construct ($id) {
if (!preg_match('~^{a-z0-9]$~i', $id)) throw new Exception("Invalid id '$id'");
$this->id = $id;
}
public function getId () { return $this->getId(); }
}
So this one is immutable and it ensures a specific format. When you type-hint against this class within another class, you don't need to test, whether or not the identifier is valid
class MyClass {
protected $id;
public function __construct (Identifier $id) { $this->id = $id; }
}
This is just a simple example and in fact it is not that common in php.
[..] and added more lines of code.
I don't think "more lines of code" is bad by itself. If it needs more lines (or even classes), to write readable and clean code, it is much much better, than compact, but unreadable stuff.
Imagine a new developer (or yourself maybe a year after you last touched the project) reading the code in the first example:
$component->repaint(false);
Without jumping to the definition of repaint() or otherwise reading your documentation for the method, you have absolutely no way of knowing what that false means in terms of how the method behaves. I mean, it literally reads "repaint false", so... repaint but... don't actually repaint? The intent is not clear, and that is a bad thing.
This extremely simple example serves to demonstrate how code readability can be greatly improved by wrapping primitives. The benefits are even greater when you want to start adding just a little bit of behavior like baking in simple validation and comparing itself against another instance.
You should have no concern at all in regards to the performance impact of new'ing up such a tiny little object. As for "more lines of code" why is that bad? SRP almost always results in "more code" but it is clean, readable and maintainable code.
I have a do...while loop and a try...catch block that wraps around database centric code. The do...while and try...catch serves the purpose of preventing transaction deadlocks, and it does so very well from extensive testing. My problem now is code redundancy. I cannot figure out a way to deploy a function or method that performs the do...while and try...catch around a generic set of database centric code without using the "evil" eval command. I imagine this comes up under other software design pattern scenarios.
This illustrates how I imagine the method with eval:
class Database {
public static function deadlockSafeTransaction($code) {
do {
// setup a condition
try {
// start transaction
eval($code); //evil
// commit transaction
}
catch(Exception $ex) {
// rollback transaction
// analyze exception for deadlock and adjust condition or rethrow exception
}
} while(condition);
}
}
This illustrates an undesired coding practice if I were to use the method above:
// code
Database::deadlockSafeTransaction("
// code - sometimes a lot of complicated code with other method calls and loops
");
// code
I am looking for a solution that does not include the use of the eval command.
After writing all of this up, I just thought of the possibility of flanking my code with include statements:
include "do-try.php";
// database code
include "catch-while.php";
But I am looking for something more OOPish and less hackish. I don't even know if the above would work and the includes may carry an unnecessary performance expense. So the issue still warrants inquiry and discussion for the best solution.
You could pass in an anonymous function:
$myFunction = function() {
// do something
};
Database::deadlockSafeTransaction($myFunction);
Call the function in your deadlockSafeTransaction code:
public static function deadlockSafeTransaction($myFunction) {
...
$return = $myFunction();
...
}
More information is available in the PHP docs. If you're using PHP < 5.3.x you can also use the call_user_func method.
Use callbacks:
function doInTransaction($fn) {
// stuff
$fn();
// more stuff
}
and then
doInTransaction(function() {
// whatever
});
As to the question how to pass the context into the function, I don't think using globals is a good idea. Much better is to pass what you need explicitly to the function:
function doInTransaction($fn) {
// stuff
$fn($this->databaseConnection, $this->logFile);
// more stuff
}
and the function should be prepared to accept what's gets passed to it:
doInTransaction(function($connection, $logFile) {
$x = $connection->xxxx
})
Even better option is to make function a Delegate and just give it the whole "parent" object:
function doInTransaction($delegate) {
// stuff
$delegate($this);
// more stuff
}
doInTransaction(function($dbObject) {
$dbObject->doSomething(...);
})
In C# you coulduse a lambda expression to do this in a type-safe way. Not sure if PHP has anything similar.
DeadlockSafeTransaction(() => DoSomething());
You can use an interface class to implement an OOP callback.
http://php.net/manual/en/language.oop5.interfaces.php
Your code would be something like:
interface databaseAction(){
public function DbActions();
}
class someClass implements databaseAction{
//regular class stuff
public function DbActions(){
//your code to be executed
}
}
Your Db class would then be this:
class Database {
public static function deadlockSafeTransaction($obj) {
do {
// setup a condition
try {
// start transaction
$obj->DbActions(); //not evil
// commit transaction
}
catch(Exception $ex) {
// rollback transaction
// analyze exception for deadlock and adjust condition or rethrow exception
}
} while(condition);
}
}