I want to set initial values of fields in an object, using $config. Which approach is better in terms of cleaner and more maintainable code?
Also, I would like to add that object will be initialized in a factory and not directly by client.
1. I pass $config to the object
<?php
class UserGreeting {
private $config;
public function __construct($config){
$this->config=$config;
}
public function greetings(){
echo 'Hello, '.$this->config->get('username');
}
}
?>
Pros:
Easy to pass multiple parameters
Cons:
The class is coupled with $config ( is it?). What I mean is that
apart from particular $config interface and parameters naming
conventions, I can't just plug this class into another program
without introducing $config
Client code doesn't have to know which parameters are used by the
object, but that is more general thought
2. I set fields manually outside the object
<?php
class UserGreetingFactory{
public function __construct($config){
$this->config=$config;
}
public function getUserGreeting(){
$userGreeting=new UserGreeting();
$userGreeting->setUserName='John Doe';
return $userGreeing;
}
}
class UserGreeting {
private userName;
public function setUserName($userName){
$this->userName=$userName;
}
public function greetings(){
echo "Hello, {$this->userName}";
}
}
?>
Pros:
The class doesn't care where his parameters are coming from
Can reuse easily
Easier to test(is it?). I mean that I don't have to deal with setting
up $config
Cons:
Factory\Builder has to know which parameers to pass
Lots of extra code for setters and passing parameters
First solution with ctor injection. But instead of a special config i would just pass the actual objects. In your case an User object.
<?php
class UserGreeting
{
private $user;
public function __construct(User $user)
{
$this->user = $user;
}
public function greet()
{
printf('Hello, %s!', $this->user->getName());
}
}
Considering your idea's, I'd stick to a single variable. If you want to pass the variables per-method you'll have a lot of excessive code.
From an OOP point of view, you shouldn't put it in a single variable. An object has properties. An username is in fact a property so you should use it as property. That means that in PHP classes you'd need to make it a public variable and set the variables when you create the object.
The first way is better because of dependency injection. This code will be easier to test and to maintain.
The third way is to use Visitor pattern to inject dependencies.
You could use a static class with static methods. In effect they are like CONSTS, but you can enforce all kinds of rules within the static config class - that they conform to an interface for example.
Config::getUserName();
That way if you are going to be faced with a family of config objects, you can be assured they all have at least an entry for each expected value - otherwise a warning is chucked.
Might depend on your situation of course, and I expect there are many situations where you would not want to do this - but I will offer it up all the same.
Related
I was wondering what is the best way to transfer an instanced object into another class for local usage. I am also curious if this makes a differences with regards to memory usage.
I figured, there are mainly two ways:
1.) Transfer instanced objects via referencing to $GLOBALS:
class UserLogHandler {
public function __construct() {
$this->DB = $GLOBALS['DB'];
$this->Security = $GLOBALS['Security'];
}
public function doSomeWork() {
$this->DB->someMethod;
}
}
or
2.) Transfer via handover:
class UserLogHandler($DB,$Security) {
public function doSomeWork() {
$DB->someMethod;
}
}
It seems to me, that option 2 might be better suited for a complicated environment, although I find option 1 more appealing. Anyhow I would prefer a technical and/or logical explanation why to use one option over the other. If there is another, better option please let me know as well.
Thanks in advance and best wishes,
Thomas
This is indeed a good question. I will say it depends upon your need. Lets analyze both your options one by one.
Before starting, keep in mind that your object should always a complete object. It should not have a incomplete state. You can refer to this article for more understanding https://matthiasnoback.nl/2018/07/objects-should-be-constructed-in-one-go/
1.) Transfer instanced objects via referencing to $GLOBALS:
You must never use such methods as they are confusing. $GLOBALS lacks to tell you where and how a particular variable was created so You can't never be sure if this variable exist or what it holds. I will suggest you to use dependency injection for it
use DB;
use Security;
class UserLogHandler
{
public function __construct(DB $DB, Security $Security)
{
$this->DB = $DB;
$this->Security = $Security;
}
public function doSomeWork()
{
$this->DB->someMethod;
}
}
See how you can now be sure that from where $DB and $Security where injected and what they hold. You can even enforce type of variable using type indication like Security $Security.
This method comes handy when your class is heavy dependent on a particular variable. e.g. A model class will always need DB adapter or a PDF generator library will need PDF class essentially.
2.) Transfer via handover
This works as you expected but I think you made mistake while defining it. You need to write it like following.
class UserLogHandler
{
public function doSomeWork($DB, $Security)
{
$DB->someMethod;
}
}
This method comes handy when you need a particular variable in a particular function only. Example for it, will be like we need to get records from a model for some particular condition. So we can pass value in function and get results according to value.
use DB;
use Security;
class UserLogHandler
{
public function __construct(DB $DB, $Security)
{
$this->DB = $DB;
$this->Security = $Security;
}
public function doSomeWork($value)
{
if ($value = 'something') {
$this->DB->someMethod;
}
}
}
As you can see that both methods can be used in conjugation. It only depends what is your requirement
I have these classes:
class User{
private $user_ID;
private $first_name;
private $surname;
...
private $website;
private $company;
function __construct($array){
$this->user_ID = $array["userId"];
$this->first_name = $array["first"];
$this->surname = $array["last"];
$this->telephone = $array["tele"];
...
}
public function addWebsite($array){
$this->website = $array;
}
public function addCompany($array){
$this->company = $array;
}
public function getData(){
$array = array();
foreach($this as $var => $value) {
$array[$var] = $value;
}
return $array;
}
}
class Website{
private $webId;
private $url;
private $description;
...
function __contruct($array){
$this->webId = $array["webId"];
$this->url = $array["url"];
$this->description = $array["desc"];
...
}
}
the getData() method in User is exactly the same for the Website class.
so how can i get the website class to implement this method? But ONLY the getData() method
While inheritance forms an behaves-as relationship, this is not a situation for Inheritance. Your Website is not related to the User in any way, so there shouldn't be a relationship between them.
Having base classes like suggested elsewhere here will quickly lead to monolithic architecture and god objects. Those in turn lead to less maintainability, high coupling, fragile code and hampers reuse. Likewise, making everything public or resorting to similar means that defeat information hiding and widen the public API lead to similar problems and you will want to avoid them.
What you are looking for is Traits, but these are only supported as of PHP 5.4. The easiest approach is really just to duplicate that method in both classes. Keep in mind that you usually want to avoid code duplication, but in this case its the lesser evil over the other suggested alternatives.
A viable alternative would be to use an Introspection Service that uses Reflection to fetch the data from the object into an array. Although in general, you should put methods on the objects having the data the methods operate on.
if you are using php5.4 you can use traits instead of classes. It´s solve the cases witch you need the implementation of one method in two diferents classes.
To make it type save you can define an interface for example "arraySerializable" which has the getData method. You can use this interface later in TypeHints instead of the class.
But this still doesn't give you the functionality. I suppose a common base class is not the thing you want here. So if you can't use traits you have to duplicate the code. This might be one of the rare cases where some lines duplicated code is ok.
Make another class that only has the getData method, and make both of your existing classes extend that new class.
If you do not have Traits there was an older implementation of Mixins that you could use.
You may know that:
<?php
class A {
public function B() {
var_dump($this->data);
}
}
class X {
protected $data;
public function Y() {
A::B()
}
}
$x = new X;
$x->Y(); // will execute the code for A::B
// but will assume the object context
// of $x (of class X) and will have
// access to $this->data
// ! this is not a static call
Using this principle you can create a static array of class names and/or method names that you can "mix-in" or "use" (like traits) via the magic method __get.
?>
As opposed to the other answerers, I think I should comment on your design. You want to create a method that exposes all private properties of any object. An object is, in most cases, somewhat more than simply a property bag, so in what situations would you need to know all properties? And why do you then mark them as private?
To solve the real problem, you should take a look at public properties, or private ones with getters and setters if you want to control the incoming and outgoing data.
If you however think you need all properties of a given object (and are willing to accept "hacks" like copypaste-programming, traits and whatnot), why not simply mark them as public and call get_object_vars()?
I have some code that often looks like this:
private $user;
public function __construct()
{
$this->user = User::getInstance(); //singleton
}
public function methodOne()
{
return $this->user->foo();
}
public function methodTwo()
{
return $this->user->foo2();
}
public function methodThree()
{
return $this->user->foo3();
}
I figure if I set user property to the instance I can reuse a shorter name in my methods (well in this case it's not that much shorter). I also thought doing it this way might save a little resources (beginning to doubt it), but when I look at other people's code I rarely see people do this. They would usually just call:
User::getInstance()->foo();
User::getInstance()->foo2();
User::getInstance()->foo3();
Is there any sort of best practice for this? Maybe if it's not a singleton class you might do it this way? Or maybe you should never do it this way? Hope to get some clarification, thanks.
Edit:
Incase there is any misunderstanding I'm just wondering if I should the first example with creating a property to store the instance vs this:
public function methodOne()
{
return User::getInstance()->foo();
}
public function methodTwo()
{
return User::getInstance()->foo2();
}
public function methodThree()
{
return User::getInstance()->foo3();
}
Actually now that I think about it this may be less code as I don't need the constructor...
There are indeed some problems with your approach.
It is not clear that your class depends on the User class. You can solve this with adding User as a constructor parameter.
Singletons are often bad practice. Your code demonstrates why: it is globally accessible and hence difficult to track dependencies using it (this points to the above problem).
Static methods are too often used as global access points (in response to what you see people usually do User::method()). Global access points give the same problem as singletons. They are also a tad more difficult to test.
I also don't see the point in repeating the User object with your new object, unless you would use eg the adapter pattern. Maybe if you could clarify this I would be able to come up with a better alternative than the generic:
class Foo {
public function __construct(User $user) {
$this->user = $user;
}
public function doXsimplified() {
$this->user->doXbutMoreComplex($arg1,$arg2, $arg20);
}
}
My personal preference in PHP is to use classes with just static methods for singletons, so you have
User::foo();
User::bar();
I would not create a new class just to wrap around a singleton like that. But if your new class adds some extra logic then your example makes sense. Remember, if you're worried that you're too verbose you can always use a temporary variable for successive function calls.
$user = User::getInstance();
$user->foo();
$user->bar();
But personally, I don't use Singletons anymore. Instead, I use Dependency Injection. I like the sfServiceContainer, but there are others. Have a look at this series of articles: http://fabien.potencier.org/article/11/what-is-dependency-injection
UPDATE
Based on the additional comments, this is how I would do it:
class UserWrapper
{
private $user = null;
public function __construct($user)
{
$this->user = $user;
}
public function foo()
{
return $this->user->foo();
}
...
}
Then use it like this:
$user = new UserWrapper(User::getInstance());
Why? So I can pass in a fake User object if I want to test the UserWrapper class. E.g:
class UserMock { ... } // A fake object that looks like a User
$userTest = new UserWrapper(new UserMock());
I usually go like this, if you have already included the class in a bootstrap of some sort or a config file. I would usually declear the $user variable in a bootstrap that will get called on every page load, then just reference it as a global variable on other php files, this is what I would have in the bootstrap file.
$user = new User();
Then this is what I would have in the calling php file
global $user;
$user->foo();
Say I have a class which represents a person, a variable within that class would be $name.
Previously, In my scripts I would create an instance of the object then set the name by just using:
$object->name = "x";
However, I was told this was not best practice? That I should have a function set_name() or something similar like this:
function set_name($name)
{
$this->name=$name;
}
Is this correct?
If in this example I want to insert a new "person" record into the db, how do I pass all the information about the person ie $name, $age, $address, $phone etc to the class in order to insert it, should I do:
function set($data)
{
$this->name= $data['name'];
$this->age = $data['age'];
etc
etc
}
Then send it an array? Would this be best practice? or could someone please recommend best practice?
You should have setter/getter methods. They are a pain but you don't necessarily have to write them yourself. An IDE (for example Eclipse or Netbeans) can generate these for you automatically as long as you provide the class member. If, however, you don't want to deal with this at all and you're on PHP5 you can use its magic methods to address the issue:
protected $_data=array();
public function __call($method, $args) {
switch (substr($method, 0, 3)) {
case 'get' :
$key = strtolower(substr($method,3));
$data = $this->_data[$key];
return $data;
break;
case 'set' :
$key = strtolower(substr($method,3));
$this->_data[$key] = isset($args[0]) ? $args[0] : null;
return $this;
break;
default :
die("Fatal error: Call to undefined function " . $method);
}
}
This code will run every time you use a nonexistent method starting with set or get. So you can now set/get (and implicitly declare) variables like so:
$object->setName('Bob');
$object->setHairColor('green');
echo $object->getName(); //Outputs Bob
echo $object->getHairColor(); //Outputs Green
No need to declare members or setter/getter functions. If in the future you need to add functionality to a set/get method you simply declare it, essentially overriding the magic method.
Also since the setter method returns $this you can chain them like so:
$object->setName('Bob')
->setHairColor('green')
->setAddress('someplace');
which makes for code that is both easy to write and read.
The only downside to this approach is that it makes your class structure more difficult to discern. Since you're essentially declaring members and methods on run time, you have to dump the object during execution to see what it contains, rather than reading the class.
If your class needs to declare a clearly defined interface (because it's a library and/or you want phpdoc to generate the API documentation) I'd strongly advise declaring public facing set/get methods along with the above code.
Using explicit getters and setters for properties on the object (like the example you gave for set_name) instead of directly accessing them gives you (among others) the following advantages:
You can change the 'internal' implementation without having to modify any external calls. This way 'outside' code does not need change so often (because you provide a consistent means of access).
You provide very explicitly which properties are meant to be used / called from outside the class. This will prove very useful if other people start using your class.
The above reasons is why this could be considered best practice although it's not really necessary to do so (and could be considered overkill for some uses ; for example when your object is doing very little 'processing' but merely acts as a placeholder for 'data').
I perfectly agree with CristopheD (voted up). I'd just add a good practice when creating a new person.
Usually, a use a constructor which accept the mandatory fields and set the default values for the optional fields. Something like:
class Person
{
private $name;
private $surname;
private $sex;
// Male is the default sex, in this case
function Person($name, $surname, $sex='m'){
$this->name = $name;
$this->surname = $surname;
$this->sex = $sex;
}
// Getter for name
function getName()
{
return $this->name;
}
// Might be needed after a trip to Casablanca
function setSex($sex)
{
$this->sex = $sex;
}
}
Obviously, you could use the setter method in the constructor (note the duplicate code for the sex setter).
To go full OOP, you should do something similar to:
class User {
private $_username;
private $_email;
public function getUsername() {
return $this->_username;
}
public function setUsername($p) {
$this->_username = $p;
}
...
public function __construct() {
$this->setId(-1);
$this->setUsername("guest");
$this->setEmail("");
}
public function saveOrUpdate() {
System::getInstance()->saveOrUpdate($this);
}
}
If you want to save a user, you just create one, assign its values using Setters and do $user->saveOrUpdate(), and have another class to handle all the saving logic.
As a counterpoint to ChristopheD's answer, if your instance variable is strictly for private use, I wouldn't bother with writing a getter & setter, and just declare the instance variable private.
If other objects need to access the object, you can always add a getter. (This exposes another problem, in that other classes might be able to change the object returned by the getter. But your getter could always return a copy of the instance variable.)
In addition using a getter/setter also shields other parts of the same class from knowing about its own implementation, which I've found very useful on occasion!
From a more general point of view both direct access ($person->name) and accessor methods ($person->getName) are considered harmful. In OOP, objects should not share any knowledge about their internal structure, and only execute messages sent to them. Example:
// BAD
function drawPerson($person) {
echo $person->name; // or ->getName(), doesn't matter
}
$me = getPersonFromDB();
drawPerson($me);
// BETTER
class Person ....
function draw() {
echo $this->name;
}
$me = getPersonFromDB();
$me->draw();
more reading: http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html
First of all, I do not want to extend a class. I would ideally like to do this.
public function __construct() {
/* Set Framework Variable */
global $Five;
$this =& $Five;
}
I have a system where the variable $Five is a container class which contains other libraries. I could assign this to a local variable of Five... i.e.
public function __construct() {
/* Set Framework Variable */
global $Five;
$this->Five = $Five;
}
However, the reason why I am trying to avoid this is that function calls would be getting a little long.
$this->Five->load->library('library_name');
Its a little ugly. Far better would be.
$this->load->library('library_name');
What is the best solution for this?
I think that
$this->Five->load->library('library_name');
is going to be your best option unless you decide to have the class extend the helper class. AKA
class Something extends Helper_Class
However, this means that Helper_Class is instantiated every time you instantiate a class.
Another method would be to have a pseudo-static class that assigned all of the helper classes to class members
public function setGlobals($five)
{
$this->loader = $five->loader;
}
Then just call it
public function __construct($five)
{
someClass::setGlobals($five);
}
If $Five is a global, you could just global $Five everytime you want to use it, but putting that at the top of every function just seems like bad coding.
Also, I'd just like to do my public service announcement that Global variables are generally a bad idea, and you might want to search 'Dependency Injection' or alternative to globals. AKA
public function __construct($five);
instead of
global $five;
Globals rely on an outside variable to be present and already set, while dependency injection requests a variable that it is assuming to be an instance of the Five class.
If you are running PHP 5.1 (Thanks Gordon), you can insure the variable is an instance of the FiveClass by doing this:
public function__construct(FiveClass $five);
$this is a reference to the current instance of the class you are defining. I do not believe you can assign to it. If Five is a global you ought to be able to just do this:
$Five->load->library('library_name');
You might wanna go with some kind of implementation of the dependency injection pattern:
Dependency injection (DI) in computer
programming refers to the process of
supplying an external dependency to a
software component. It is a specific
form of inversion of control where the
concern being inverted is the process
of obtaining the needed dependency.
See also the documentation for the symfony DI container. I can highly recommend this DI container implementation if you want to improve the way you handle your 'globals'.
You could also have a read of this question on 'best ways to access global objects'.
How about making the relevant data members and methods of Five static class members? This
$this->Five->load->library('library_name');
would become this
Five::load->library('library_name');
and you wouldn't have to pass &$Five around everywhere.
You cannot overwrite $this (like e.g. in C++) but you can easily build an aggregate using __call() for method calls and __get(), __set(), __isset() for properties.
Example for __call():
class Five {
public function bar() {
echo __METHOD__, " invoked\n";
}
}
class Foo {
protected $Five = null;
public function __construct(Five $five=null) {
if ( is_object($five) ) {
$this->Five = $five;
}
}
public function __call($name, $args) {
// there's no accessible method {$name} in the call context
// let's see if there is one for the object stored in $five
// and if there is, call it.
$ctx = array($this->Five, $name);
if ( !is_null($this->Five) && is_callable($ctx) ) {
return call_user_func_array($ctx, $args);
}
else {
// ....
}
}
}
$foo = new Foo(new Five);
$foo->bar();
prints Five::bar invoked.
In my opinion the biggest draw back is that it is much harder to see "from the outside" what the object is capable of.
I'm pretty sure you can't reassign $this, as it's one of those special things that looks like a variable in PHP, but is treated slightly differently behind the scenes.
If your concerns are the semantics of your method calling getting too long, I'd make load a method call instead of an object property
$this->load()->library('library_name');
public function load()
{
return $this->Five;
}
maybe better for you will be to use PHP Magic Methods?
http://www.php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.methods