I just stumbled over a PHP class and wonder if there was a valid reason for the way one of it's methods is written.
LogUtility::getLogger() is called as a static method in various other PHP classes of the PHP application. Does the used if statement make sense or is $logManager always null when getLogger() is called?
class LogUtility
{
/**
* #var LogManager
*/
protected static $logManager;
/**
* #return Logger
*/
public static function getLogger($name)
{
if (!self::$logManager) {
self::$logManager = GeneralUtility::makeInstance(LogManager::class);
}
return self::$logManager->getLogger($name);
}
}
You could quickly whip up a test, like below, and test / prove it yourself:
class someClass {
protected static $stored;
public static function test() {
echo '<br>Stored state:' . self::$stored;
if ( ! self::$stored) {
self::$stored = "set";
}
}
}
someClass::test();
someClass::test();
Output is:
Stored state:
Stored state:set
So, based on this simple test, the answer is Yes, the if statement makes sense. The static variable is set and maintained.
$logManager is set to a property of the class, so for now, its pretty much an empty class, just returning with a getter, the instance. This just sets the code to just reuse the object. So a bit of recycling code there.
In the class you are now able to play with this object freely. So if you run this LogUtility from another piece of code by setting it to a var, you have already instantiated it. e.g. $util = new LogUtility();now if someone comes along and tries to instantiate it again, $anotherUtil=new LogUtility(); this recycles the class, passing back the already instantiated instance, instead of instantiating a new one.
Therefore, yes, it kept it. Although, the var doesn't contain the "same value" per say, it contains a reference to the "same" class that was instantiated with he other variable, so it ends up a copy of the same instance there.
It will be null for only the first call in a lifecycle. This implements a design pattern called Singleton.
Check out https://sourcemaking.com/design_patterns/singleton/php/1
Related
I'm trying to write a class in PHP that acts as a wrapper for a collection of command line tools to make them easier to use from PHP.
I have a single class (MyClass) in a file myclass.php.
I have code that checks to see if the required tools are installed and then sets a constant (TOOLS_AVAILABLE) to either true or false. Although it's not a lot of code, I only want it to run the first time somebody tries to instantiate my class or use any of its static functions. What's the best practice for handling this?
I only want it to run the first time somebody tries to instantiate my class or use any of its static functions.
Well, the best answer is not to have any static methods. Then you can stick the code in a constructor method as per the answer by #treegarden.
If you must have static methods, then you'll need a static flag within the class to indicate when you've called the 'run once' code, so you can avoid running it again. And then call it explicitly from each of your static methods and the constructor. Something like this:
<?php
class myClass {
private static $hasRunOnce = false;
private static runMeOnce()
{
if (!self::$hasRunOnce) {
self::$hasRunOnce = true;
//put your 'run once' code here...
}
}
public static oneOfYourStaticMethods()
{
self::runMeOnce();
//put your static method code here...
//this would be the same for each of your static methods and your constructor.
}
}
Hope that helps.
You need to create a __construct function in your class and put whatever code you want to execute on instantiation in there:
class MyClass {
function __construct(/* arguments */) {
/* your code here */
}
}
The code will get executed only once when someone instantiates the class.
I understand OOP. What I understand so far is that private and protected cannot be referenced from outside the class using $this->blah notation. If that is correct, how can the following code work?
<?php
class test {
protected $a = "b";
public static function oo(){
$instance = new static();
echo $instance->a;
}
}
test::oo();
Gives me an output of b! Now, how in Lord's name can that happen?
In PHP 5.3, a new feature called late static bindings was added – and this can help us get the polymorphic behavior that may be preferable in this situation. In simplest terms, late static bindings means that a call to a static function that is inherited will “bind” to the calling class at runtime. So, if we use late static binding it would mean that when we make a call to “test::oo();”, then the oo() function in the test class will be called.after that you return $instance->a; static keyword allows the function to bind to the calling class at runtime.so if you use static then whatever access modifier(private,public,protected) you use it's just meaning less...
please read this link,another
That happens because you're "presenting it" by echo'ing it. You can't reference it like this for example:
class test {
private $a = 'b';
function __construct() {
echo 'instantiated';
}
}
$test = new test();
echo $test->a; // This line won't work, since it's a private var.
It would give you an error message that looks like this:
Fatal error: Cannot access private property test::$a
Example (https://eval.in/226435)
As I said before, you're accessing it from within the class itself, so you CAN view it. (That's the $instance you have there.) If you modify your code to use it like this:
class test {
protected $a = "b";
public static function oo(){
$instance = new static();
return $instance;
}
}
echo test::oo()->a;
Example of the above (https://eval.in/226439)
You'll get that "private acess blah blah" error.
You're understanding the statement wrong. "private and protected cannot be referenced from outside the class" means that as the examples above show, you CAN NOT access the variables outside the class, but with your example, you're accessing it from INSIDE the class, which means they'll do as you require (echo'ing out as you did)
What I understand so far is that private and protected cannot be referenced from outside the class
As follows, since oo is defined in the same type as a, oo has access to a.
This is actually a very good question, and shouldn't be down-voted.
From what I understand, the reason why you can access a protected/private property from within a static method of the same class, is because "the implementation specific details are already known when inside this class". I rephrased this a little from what is documented on the official page on Visibility:
Objects of the same type will have access to each others private and protected members even though they are not the same instances. This is because the implementation specific details are already known when inside those objects.
This makes sense. Visibility access is meant to only expose things that are safe for the public to use. But if you already have access to the code of the Class you're using, then there is no point of preventing you to use what you already see. Hope that makes sense..
I've been programming in PHP for several years and I've only just recently begun to look at object oriented code. Now I understand classes and such:
class Myclass {
public function __construct() {
}
}
and all that good stuff... I also understand creating functions and calling in my index.php:
$someVar = new Myclass;
One thing I've been trying to understand, being that i've recently looked at codeigniter and I like one thing about it and want to try and accomplish the same thing without actually using codeigniter.
in code igniter they have the variable $this appear to be their class variable. But by using that, you're able to call from multiple classes all at once.. such as:
$this->load->module(); which is in one class file..
$this->db->query(); which is in another class file.
I've searched google for the last few days trying to figure out how to do this same thing where each class would have the correlation between them all allowing me to run $this->class_name->function_name in my projects instead of creating a new variable for each class or for the sake of a clean index file, having every function in a single class file.
Any information (aside from buy this book - as that isn't an option for me) is greatly appreciated and I will thank you now (and will probably thank you again later just for good measure).
I've been reading you and Phil's comments. First off, you can't use $this on index.php. $this can only be used in the context of an object. So you could do,
$someVar = new Myclass;
...
$someVar->db->something();
...instead.
I'm not entirely sure what you mean by "read classes," but you can assign members to MyClass exactly as Phil indicates:
class MyClass {
private $inj;
function __construct(Injected $inj) {
$this->injected = $inj;
}
}
Note that the private $inj declaration is not mandatory, but skipping it is dangerous. Any non-declared members added are automatically public, and this can potentially screw with you if you rely on magical get. I would declare the properties you need.
Finally, you either need to include all class definitions you will use, use a function like load_class(), or use autoloading. If Injected above is not a declared class, you will get an error when trying to create one. load_class() almost certainly includes the class definition somehow.
The load and db references are class properties which are themselves other objects with public module() and query() methods respectively. For example
class MyClass
{
/**
* #var CI_DB
*/
private $db;
/**
* #var Loader
*/
private $load;
public function __construct(CI_DB $db, Loader $load)
{
$this->db = $db;
$this->load = $load;
// PHP also allows you to add arbitrary object properties
// that receive a "public" visibility
// Please note, this is not a good practice
$this->foo = new Foo;
}
public function someMethod()
{
$this->load->module();
$this->db->query();
// You can also use foo even though it is not defined
// in the class properties
$this->foo->something();
}
}
See http://www.php.net/manual/en/language.oop5.properties.php
Adding the foo property like we did is dangerous. Because it receives the public visibility, it may be altered externally to the class.
$class = new MyClass($db, $load);
$class->foo = new Bar;
$class->someMethod(); // will break if Bar does not contain a something() method
As the title says, I'm wanting to create an instance of a class from within a static method of the same class. I've figured out so far is that I can by doing something like this:
class Foo{
public $val;
public static function bar($val){
$inst = new Foo;
$inst->val = $val;
return $inst;
}
}
Which therefore lets me do this.
$obj = Foo::bar("some variable");
Which is great.
So now the questions. Is there an easier way of doing this that I'm not aware of, or any shortcuts to achieving the same result? Are there any advantages or disadvantages of creating an instance in this fashion?
Thanks.
They way you're doing it is fine. There are a few other things that can make your life easier that you can do as well.
Don't hardcode the class name. If you're on 5.3+, use the keyword static. That way, if you extend the class, the new function can instantiate that one as well:
public static function bar($var) {
$obj = new static();
$obj->var = $var;
return $obj;
}
Then you can use it in any extending class without needing to override anything.
Figure out if $var should be passed in through a constructor rather than set after construction. If the object depends upon it, you should require it.
public function __construct($var) {
$this->var = $var;
}
That way you can't instantiate the object without setting the variable.
Enforce the instantiation of the class through the static method. If you're doing anything in there that you need to do, then make the constructor either protected or private. That way, someone can't bypass the static method.
protected function __construct() {}
private function __construct() {}
Edit: Based on your comment above, it sounds to me like you're trying to implement the Singleton Design Pattern. There's tons of information out there about why it's not a great idea and the bad things it may do. It has uses as well.
But there are a few other patterns that may be of use to you depending on what you're doing exactly.
You can use the Factory Method if you're trying to create different objects using the same steps.
If all of the objects start off the same and then are customized, you could use the Prototype Pattern.
You could use an Object Pool if it's particularly expensive to create your object.
But one thing to consider, is that in PHP objects are pretty light weight. Don't try to avoid creating a new object just for that overhead. Avoid doing heavy things like database queries or filesystem accesses multiple times. But don't worry about calling new Foo() unless foo's constructor is particularly heavy...
This looks like a simple factory method pattern.
You have a nice advantage: suppose that in the future you want to start using a different implementation (but that does the same thing). Using a factory you can change all the objects that are created in many places of a complex system simply by changing the creator method. Note that this would work easier if you used an external class (as is in the first link below).
Keeping it as you have now, you can also subclass this class and override the method to create a more complex object. I don't think this is what you want to achieve in here.
Anyway, this is good to enable Test Driven Development, abstraction and lots of other good things.
links:
Php patterns
Factory method pattern on wikipedia
If you're just creating an object, this isn't very usefull. You could just call a constructor. But if you're doing something more complicated (like you're starting with some sort of singleton pattern but haven't included all the details in this example), then:
This sounds about right. If you want to prevent objects created in the default way like this:
$obj = new Foo("Some Variable");
You can add a private constructor:
class Foo{
public $val;
private __construct(){}
public static function bar($val){
$inst = new Foo;
$inst->val = $val;
return $inst;
}
}
Now you enforce people to use your static class. The need to set the val in the function might be gone, so you could even add the value-parameter to your private constructor but do the other things (that you presumably want to do, like check for some sort of singleton pattern) in your 'bar' function
Super late but found this useful.
A good example of this in the wild is this static method from Audi's UI library returning an Array of instantiated TextField classes from within TextField's static method upgradeElements.
/**
* Class constructor for Textfield AUI component.
* Implements AUI component design pattern defined at:
* https://github.com/...
*
* #param {HTMLElement} element The element that will be upgraded.
*/
export default class Textfield extends Component {
/**
* Upgrades all Textfield AUI components.
* #returns {Array} Returns an array of all newly upgraded components.
*/
static upgradeElements() {
let components = [];
Array.from(document.querySelectorAll(SELECTOR_COMPONENT)).forEach(element => {
if (!Component.isElementUpgraded(element)) {
components.push(new Textfield(element));
}
});
return components;
};
constructor(element) {
super(element);
}
...
See the rest in the repo
https://github.com/audi/audi-ui/blob/master/src/textfield/textfield.js#L25
It seems as though different instances of a class can know about each others' private member variables.
I have provided some code that attempts to showcase my issue, and I will try to explain it.
We have a class with a private member variable, $hidden. modifyPrivateMember sets the value of $hidden to 3. accessPrivateMember takes an Object as a parameter and accesses its private $hidden member to return its value.
Example code:
<?php
// example.php
class Object {
private $hidden;
public function modifyPrivateMember() {
$this->hidden = 3;
}
public function accessPrivateMember(Object $otherObject) {
return $otherObject->hidden;
}
}
$firstObject = new Object;
$firstObject->modifyPrivateMember();
$otherObject = new Object;
echo $otherObject->accessPrivateMember($firstObject);
Output of the above code:
$ php example.php
3
Can anyone explain why private members of objects are accessible to other instances of the same class? Is there some justification for this ostensible breach of scope?
private means it's restricted to only that class, not only that object.
That's just how php works. It's the same as how Java works. See http://php.net/manual/en/language.oop5.visibility.php for more info.
The only situation in which this behavior seemed useful was in a factory function:
class Object
{
private $state;
public static function makeObject()
{
$obj = new Object;
$obj->state = 'some state';
return $obj;
}
}
Even in this case, there are better solution and I agree with you that it is a breach of scope, although not that big in my opinion. After all, the one who writes the class decides if she needs to access private members from objects passed as arguments. So, it may seem useless (even to me), but you never know. It's not like you're exposing your internals to subclasses or something. It all happens in the same class and it's your business what you're doing in there.
By the way, one language that implements access modifiers per object and not per class is Ruby.