I thought I was pretty comfortable with the fundamentals of OOP in a few languages like Python and PHP, but I got a bit confused trying to figure out what's going on in certain situations in CakePHP.
Say for example I'm in a controller called TestsController but I want to look up data from another controller, such as OthersController. I'd do something like this
$this->loadmodel('Other');
$this->Other->find('all');
I understand that $this is a reference to the object of the class you're in, and Other clearly refers to OthersController, but what exactly is Other? Is it some kind of initialization variable? An Object? Something else? Does $this->Other become an object itself? If so, how does PHP/CakePHP do this, or is it just something inherent of PHP that it just "knows" to do so.
I found this example of something called method chaining, but it looks like using one object to call many actions.
<?php
class MyClass{
public $prop1 = "I'm a class property!";
}
$obj = new MyClass;
echo $obj->prop1; // Output the property
?>
I understand with $obj you're accessing $prop1, but what's happening in CakePHP when there's something like $obj->SomeModel->action()?
If possible could you modify that little OOP example to mimic that of CakePHP?
In your example, $this->loadmodel('Other') populates $this->Other with the model object you asked for. So you can treat it as a typical object (call methods, access properties, etc.). You could even do this:
$this->loadmodel('Other');
$other = $this->Other;
$other->find('all');
$other is assigned a reference to $this->Other, so they will both act exactly the same.
As for chaining, let's say that $this->Other->find('all') returns another object of the type ResultSet, and the ResultSet class has the method getNumResults(). Chaining means you could do something like this:
echo $this->Other->find('all')->getNumResults();
As long as each method you're calling in the chain returns another object, you can keep calling the methods on that object.
$this->loadmodel('Other');
$this->Other->find('all');
I understand that $this is a reference to the object of the class
you're in, and Other clearly refers to OthersController, but what
exactly is Other? Is it some kind of initialization variable? An
Object? Something else? Does $this->Other become an object itself? If
so, how does PHP/CakePHP do this, or is it just something inherent of
PHP that it just "knows" to do so.
Other does not refer to OthersController, it refers to an Other model. Cake automatically loads the model named Other inside OthersController (it infers the relationship from their names), but inside any other controller $this->Other is not available unless you explicitly load the model by calling $this->loadmodel('Other') first. This is what the snippet above does.
Even when the model is loaded by Cake, this is still done explicitly (even though it's transparent to you) inside the constructClasses method.
From the point that the model is loaded onwards, it is accessible through $controller->ModelName as any other object.
Adding to Jon answer, PHP frameworks do a lot of MAGIC.
I find myself learning about magic getter / setters, and much things like that.
For example, the Yii ActiveRecord, each row in database is an object.
So you, for example do this to load a record:
$user1 = User::model()->findByPk('1');
$user1->name = 'Jorge';
$user1->save;
So, it will take time until you start to actually comprehend what the framework is doing.
I bet that when you do $this->load->('model'); it fills something, it loads the model in some structure, maybe an array, and replacing the magic getters/setters you can actually say that when going for $this->modelName you actually are going to $this->modelsArray['modelName'].
An example without data validation:
class MyClass
{
private $arrayExample = array( 'value1'=>123, 'value2'=>234);
public function __get( $property )
{
if( array_key_exists( $this->arrayExample, $property )
return $this->arrayExample[$property];
return 'undefined';
}
}
$class = new MyClass;
echo $class->value1; //outputs 123
echo $class->value0; //outputs undefined
Related
Every example I've seen for defining a variable in a class, does so outside of any methods, for example:
class Testclass
{
public $testvar = "default value";
function dosomething()
{
echo $this->testvar;
}
}
$Testclass = new Testclass();
$Testclass->testvar = "another value";
$Testclass->dosomething();
How would you go about defining a variable inside a method, and making that definition available to any other method inside that class?
Note that I would only want to define the variable in one function, not have a different definition for each function.
I think you should read up on good object oriented practices. I mean, why do you want to make a variable available "inside a method"?
Variable's created within methods are local to that specific method and as such, scope is restricted to it.
You should instead use a instance member/variable which is available object wide if your trying to access a variable between methods. Or possibly you could pass the variable by ref between methods. Of course if its a value which never changes then it should be static variable on the class (class member).
I suggest having a read of the the OO tutorial on tutsplus. Tutsplus are generally great quality. http://code.tutsplus.com/tutorials/object-oriented-php-for-beginners--net-12762
Alternatively, you could do the OO python course (intro to computer science) on Udacity - its also very high quality. Don't worry that its Python, specific language and syntax is irrelevant when trying to understand core OO concepts. https://www.udacity.com/course/cs101
Also, this is a common topic so have a search around, ie Passing Variables between methods?
I hope that helps
Edit: to address your comment. something like this:
class Testclass
{
private $csvResult = []; // instance member array to store csv results
function dosomething()
{
$this->$csvResult = fgetcsv($blah);
}
function processResult()
{
foreach ($this->$csvResult as $item) {
var_dump($item)
}
}
}
But again, as Adrian Cid Almaguer mentioned, you really are best to build a solid foundation of OO for yourself instead of just using this example without truly understanding it.
The real name of the variables class is "properties". You may also see them referred to using other terms such as "attributes" or "fields". In OOP (Object Oriented Programming) You can't define a property inside a method (the real name of a class function is method, not function), because this is a attribute of a class, not an attribute
of a method.
The properties define the attributes of a class, and the methods defines the behavior of a class. For example if you have a class named Person, the person have Name and Age, they are your properties, they are the attributes that describe your class, they can't be inside a method that describe a behavior of your class because the properties of your class must be accessed from any method that need it to show his behavior.
You can read some examples in:
http://www.killerphp.com/tutorials/object-oriented-php/
Consider this hypothetical scenario:
I have a Stomach class, which has a contents property, to which objects of class Food should be assigned. One way to do that would be to use a kind of a setter, e.g. setContents($food).
But lets suppose that we assign food directly, as in $stomach->contents = $orange.
Suppose also that whenever a Food object is assigned to contents we need to change the object's eaten property to true. Is there a way to do that without using a method of an object that it's being assigned to (in this case, the $stomach's setter)?
Basically, my question is: can we call a method whenever an object is assigned as a property to another object? Also, even if it is possible, is it bad design? Sorry if this is a stupid question, all of this is pretty new to me.
The best OOP solution here would be to create a method that indicates an action, like eat().
To ensure that the right Object is eaten, you could define an Interface (Say Food). This interface may define a method setEaten(). The Stomach (though I would prefer Mammal or something similar that actually can eat) can then call setEaten().
Since it created some controversy in the comments, I want to point out that an object definition should as closely as possible reflect what it actually does. To reduce object coupling it is best to avoid directly accessing object properties from an other class, however there is nothing wrong with using setters instead of actions when it makes sense (note that I used one in the definition of Food), and it may often depend on the developer view.
However, here it makes sense. Consider the case "A monkey eats a banana" (for simplicity please allow me to just materialize that banana out of thin air).
$m = new Monkey();
$m->eat(new Banana());
perfect. Now lets try a setter.
$m->setContents(new Banana());
Now we have a problem, the monkey already contains a lot of things, like bones, blood, muscles a brain, etc. So setContents makes no sense here. You could try $m->getStomach()->setContents(new Banana()) but that would just increase object coupling.
I agree with #dualed about the eat method. That said the way to acheive this to make all properties private/protected and then use __get/__set to proxy to the setters.
class Stomach {
protected $contents;
public function setContents(Food $food) {
$this->contents = $food;
$food->eaten = true;
}
public function __set($name, $value) {
$method = array($this, 'set' . $name);
if(is_callable($method)) {
return call_user_func_array($method, array($value));
}
}
public function __get($name) {
$method = array($this, 'get'.$name);
if(is_callable($method)) {
return call_user_func($method);
}
}
}
Youll notic i use is_callable as opposed to method_exists because if youre working on somehting complex with virtual methods is_callable should take those in to account whereas method_exists relies on the method being defined in the class hierarchy.
__set function will help you here. But make sure you dont have any property named contents defined in class. Do it like this
class Stomach{
private $props = array();
public __set($prop, $value){
if($prop === 'contents' and $value instanceof Food){
$this->prop[$prop] = $value;
}
}
}
I'm trying to learn when static functions should be used, and have had a difficult time finding an answer my questions. I am creating a class User, which is related to a class Group. If I have a user id and I want to get a user object from that, is it better to do something like
$existingUser = User::get($userId);
where the class is defined like this
class User()
{
public static function get($id){
$user = new User();
return $user->findById($id);
}
public function findById($id) {
//find and populate user object
}
}
or
$existingUser=new User();
$existingUser->findById($userId);
where the class is defined like this
class User()
{
public function findById($id) {
//find and populate user object
}
}
What about if I were to write a function which returns an array of Group objects based on a user id?
class User()
{
//stuff
$groupArray = Group::getAllByUserId($this->getId())
//stuff
}
or
class User()
{
//stuff
$group = new Group();
$groupArray = $group->findAllByUserId($this->getId());
//stuff
}
The second method creates an empty group object which is never used. Does it matter?
Am I misunderstanding the concept of static? I know it is useful for not having to instantiate a class, so if the function instantiates one anyway, does that kind of defeat the purpose? If so, what would be an example of when a static function would be used?
Anything else I should be considering in this over simplified example?
You don't need a static function int he case you show above.
Static functions are really just global functions with a namespace.
Use them when the global state of the application needs to be controlled, or if multiple copies of the function lead to inonsistant results.
Callbacks sometimes need to be static, especially if they are passed as a string.
I'm trying to learn when static functions should be used
Oh, it's so simple: never.
To understand it, read:
http://www.objectmentor.com/resources/articles/ocp.pdf
http://misko.hevery.com/code-reviewers-guide/flaw-brittle-global-state-singletons/
I find a good rule of thumb is thinking "If I don't have a [class-name], would I expect to be able to call [method-name]?"
If I don't have a user, would I expect to be able to call findByID?
Probably not. This is one of the exceptions I come across; a "load" or a "save" method sometimes makes sense to be static.
A perfect example of when to use non-static methods is (most methods in) a Database class - you should always have a database object before you try to run a query on it.
An example of when to use a static method would be a "helper" class, essentially a collection of handy functions. Say you have some methods that help you output HTML, you might have HTML::image(), HTML::url() and HTML::script(). On these, you shouldn't need a HTML object to create an image, URL, and so on.
As for stopping multiple copies of objects being created (one argument for using static methods), you should use a Singleton pattern instead (Google it) to ensure only one copy of the object ever exists.
You should probably check out this question on Active Record vs data mapper:
https://stackoverflow.com/questions/2169832/data-mapper-vs-active-record
One take from this question is that static methods on the class for loading/saving aren't really the core functionality of the class in most cases. Further, storing and loading is a kind of abstract concept that is separate from your class objects in most cases.
Isa "user" a data storage and retrieval object? In most cases, no, it is a person represented in your system that has various properties and functions. When you start tying the persistence of that object into the object, you break encapsulation and make it harder to maintain the code. What if next week you want to load your users out of memcache? It's hardly relevant to if a user can have some property or functionality.
Can I define a class constant inside the class constructor function ?
(based on certain conditions)
That goes against the idea of class constants - they should not be dependent on a specific instance. You should use a variable instead.
However, if you insist on doing this, are very adventurous and can install PHP extensions, you can have a look at the runkit extension that allows to modify classes and their constants at runtime. See this doc: http://www.php.net/manual/en/function.runkit-constant-add.php
I don't think you can.
It wouldn't make sense, either - a class constant can be used in a static context, where there is no constructor in the first place.
You'll have to use a variable instead - that's what they're there for.
Try look here:
http://php.net/manual/en/language.oop5.constants.php
http://php.net/manual/en/language.oop5.static.php
Hope this helps.
As far as standard instance constructors go, there is no way to do this, and as others have pointed out, it wouldn't make sense. These constructors are called per created object instance, at the point they are created. There is no guarantee this constructor would get called before some code tried to access the constant. It also doesn't make sense in that the code would get called over and over again each time a new instance was constructed, whereas a const should only get set once.
It would be nice if PHP either offered some kind of static constructor that let you set the value one time for uninitialized constants, or allowed more types of expressions when defining constants. But these are not currently features of PHP. In 2015 an RFC was made that proposed adding static class constructors, but it is, at the time of me writing this answer, still in the draft status, and has not been modified since 2017.
I think the best alternative for now is to not use constants in this kind of scenario, and instead use static methods that return the value you want. This is very simple in that it only uses the PHP language features as is (not requiring any special extensions), these static methods can be called in the standard way, and you don't need to hack the autoloading process to call some kind of initializer function that sets static variables. The method might need to rely on private static variables in order to make sure the same instance is returned every time, if an object instance is being returned. You would need to write the implementation of this method to be constant like in the sense that it will always return the same thing, but takes advantage of being able to do things you can't do with a constant, like return on object instance or rely on complex expressions or function calls. Here is an example:
final class User
{
/** #var DefinitelyPositiveInt|null */ private static $usernameMaxLength;
public static function getUsernameMaxLengthConst(): DefinitelyPositiveInt
{
if ($usernameMaxLength === null) {
$usernameMaxLength = new DefinitelyPositiveInt(40);
}
return $usernameMaxLength;
}
}
$usernameInput.maxLength = User::getUsernameMaxLengthConst();
This is still not a perfect solution because it relies on the programmer to write these in a constant like way when that is desired (always returning the same value). Also, I don't like that the best place to document the fact that it is a const is in the method name, thus making it even longer to call. I also don't like that you now have to call it as a method instead of just accessing a property, which would be syntactically nicer.
This example is essentially an implementation of a singleton, but sometimes the purpose of a singleton is to be a constant rather than just a singleton. What I mean is, you might want the instance to always exist, and it might be an immutable type (none of the properties are public or mutable, only having methods that return new objects/values).
I am sorry to break it to you but it is not possible in vanilla PHP.
I am not very sure about frameworks or extensions but I am sure that it is not possible in vanilla PHP.
I recommend you to use variables instead.
You still can't, but maybe some of these (progressively weirder) ideas (just ideas, not true solutions) will work for you:
(1) You could use a private property, with a public getter method. The property cannot be modified outside the class, such as constants, but unfortunately it is accessed as a method, not as a constant, so the syntax is not the same.
class aClass{
private $const;
function __construct($const){
$this->const=$const;
}
function const(){
return $this->const;
}
}
$var1=new aClass(1);
echo $var1->const(); //Prints 1
(2) If you really want this value to be accessed as constant from outside, you can use define () inside the constructor. Unfortunately it doesn't get tied to the class or object name (as it do when you use const, using for example myClass::myConst). Furthermore, it only works if you create a single instance of the class. The second object you create is going to throw an error for redefining the constant, because is untied.
class otherClass{
function __construct($const){
define('_CONST',$const);
}
function const(){
return _CONST;
}
}
$var2=new otherClass('2');
echo $var2->const(); //Prints 2
echo _CONST; //Prints 2
#$var3=new aClass('3'); //Notice: Constant _CONST already defined
echo _CONST; //Still prints 2!
(3) Perhaps that last problem can be solved by giving variable names to the constants, related to the object to which they belong. This may be a bit weird... but maybe it works for someone.
class onemoreClass{
private $name;
function __construct($const,$name){
$this->name=$name;
$constname=$this->name."_CONST";
define($constname,$const);
}
function const(){
return constant($this->name.'_CONST');
}
}
$name='var4';
$$name=new onemoreClass(4,$name);
echo $var4->const(); //Prints 4
echo var4_CONST; //Prints 4
$name='var5';
$$name=new onemoreClass(5,$name);
echo $var5->const(); //Prints 5
echo var5_CONST; //Prints 5
If a method creates an object and I call the method from an other object, will the last object have access to the first object's properties and methods?
There's some extraneous information there that may be confusing you.
The method and the object (in this case) are disconnected from one another. So the question becomes, are you storing the created object in a scope that the second object has access to?
In Router, in a method, in an included
file is the controller code. In the
model and in the view, I need access
to the Controller's properties and
methods. In Router, in an other
method, I want to return a controller
object to the model and the view. What
now??
If I understand the question properly, you're a bit confused about MVC. Router class is a cake internal class and should never never ever never never absolutely never ever be changed. And those "never ever" are not even copy-pasted, they are really typed.
Second, model classes don't even know anything called controller. Controller uses models, not the other way around. If your model needs something from a controller, pass it on as a parameter. Anything beyond that is just bad design.
Also, calling controller actions from a view is possible, but strongly discouraged. Controller is the one to prepare all the data for a view, therefore view has no need to access the controller (there are exceptions to this, out of scope of this question).
I recommend you read a bit about MVC, cake's typical request, and at least go through the basic blog tutorial.
If it is returned/stored somewhere, public fields and methods will be accessible.
Only if the method keeps a reference to the object that it creates.
Edit: In light of the change of tags, this answer is no longer relevant. I've left it to preserve the comments...
Original Answer:
Like this?:
public MyObject CreateObject()
{
return new MyObject() { FirstProperty = "Hello World" };
}
public Main()
{
MyObject n = CreateObject();
Console.WriteLine(n.FirstProperty);
}
Or this?:
class Program
{
MyObject _myObject;
public void CreateObject()
{
_myObject = new MyObject() { FirstProperty = "Hello World" };
}
public Main()
{
Console.WriteLine(_myObject.FirstProperty);
}
}
In either of these two cases, sure you can access properties of your object. If this is not what you meant, I'm not sure exactly how to answer your question and you'll need to clarify.