I'm having some trouble extending Classes in PHP.
Have been Googling for a while.
$a = new A();
$a->one();
$a->two();
// something like this, or...
class A {
public $test1;
public function one() {
echo "this is A-one";
$this->two();
$parent->two();
$parent->B->two();
// ...how do i do something like this (prepare it for using in instance $a)?
}
}
class B extends A {
public $test2;
public function two($test) {
echo "this is B-two";
}
}
I'm ok at procedural PHP.
Your examples are fine, but you are showing a little confusion here:
public function one() {
echo "this is A-one";
$this->two();
$parent->two();
$parent->B->two();
}
what you want is this I think:
class A
{
function one()
{
echo "A is running one\n";
$this->two();
}
function two()
{
echo "A is running two\n";
}
}
class B extends A
{
function two()
{
echo "B is running two\n";
}
}
Then you want to make an object of type B and call function "one"
$myB = new B();
$b->one();
This will output
A is running one
B is running two
This is an example of polymorphic class behavior. The superclass will know to call the current instance's version of the function "two". This is a standard feature of PHP and most object oriented languages.
Note, that a superclass never knows about subclasses, the only reason you can call the "two" method and have B's version run is because the function "two" was defined in the parent (A) class.
It can't be done. First off, class A is class B's parent, so using something with parent is right off the list.
There is a number of things that goes for a child class that does not go for a parent class:
Class B needs A to be present in order to work
Class B can do everything A can plus more
Class B has access (as far as it is allowed to access) all data of class A
None of these things is true in reverse, so together they make up the reason why you cannot call a child's function.
Have a close read of the Object Inheritance section of the PHP manual. Yes, there's a lot of information in http://us2.php.net/oop, but it may help you think about what you can get out of OOP.
here's what you can do:
class A{
public function methodOfA (){
echo "this is a method of A (and therefore also of B)";
}
}
class B extends A{
public function methodOfB (){
echo "this is a method of B";
// you can do {$this->methodOfA ()} if you want because all of A is inherited by B
}
}
$a = new A (); // $a is an A
$a->methodOfA (); // this is OK because $a is an A
// can't do {$a->methodOfB ()} because $a is not a B
$b = new B (); // $b is a B, and it is also an A, because B extends A
$b->methodOfB (); // ok because $b is a B
$b->methodOfA (); // ok becuase $b is an A
Of course, there's much more. There's a good OOP section in the php manual (in artlung's answer).
Related
I have two classes A and B, where B extends A and adds some methods. I have a class C with a method that accepts A as parameter for generalization purposes. The issue is that once inside the method, I want to access the methods of class B on the object, but I'm not able to do so. Don't get error, but have null in the return, when I have dumped the object and know that it holds data.
Sorry if it's seems ridiculous, but I'm trying to use a bahaviour that you would expect in normal inheritance. Maybe be I'm missing something and it is my fault, but have no idea of what is happening here.
Please, if you have any idea of how to do this, help me.
Some code:
public function createProject(AssociatedProjectInterface $project_data){
if(!is_a($project_data, 'class\path\GithubProject')){
throw new InvalidArgumentException('The argument needs to be of type: GithubProject.');
}
$repo = $this->client->api('repo')->create(
$project_data->getTitle(),
$project_data->getDescription(),
null,
!$project_data->getIsPrivate(),
null,
$project_data->getIssuesEnabled(),
$project_data->getWikiEnabled());
}
Thanks.
Note that PHP's type checking is very loose. It calls the method of the class that is passed. The type checking is only taking place at the moment that function is called. So in the example below, testType must be past an object of type A or a descendant of A. After that initial check, no type checking is done at all! So the function can call any method declared in A or B. If a method is declared in both, it is considered overridden and the version in B is used.
<?php
class A {
function foo() {
echo 'A:foo';
}
}
class B extends A {
function foo() {
echo 'B:foo';
}
function bar() {
echo 'B:bar';
}
}
function testType(A $a)
{
$a->foo(); // B:foo
$a->bar(); // B:bar <- This will succeed even though there's no bar() in A.
}
$a = new B();
testType($a);
What you're asking for is NOT expected in normal object-oriented inheritance, but apparently works in PHP. Normally, if a method expects an object of class A, you can pass an object of class B that extends A, but the method will treat the object as though it were of class A. This means that when you call methods inherent to B, you are calling methods that don't exist and an error should be thrown.
In php though, momma don't care. As proof run the following minimal test:
<?php
class A {
public function foo() {
echo "in foo\n";
}
}
class B extends A {
public function bar() {
echo "in bar\n";
}
}
class C {
public function test(A $b) {
$b->foo();//works, because foo exists in the A class definition
$b->bar();//also works for B, but not A
}
}
$a = new A();
$b = new B();
$c = new C();
$c->test($b);
$c->test($a);//Will throw an error because the method bar() is not found
Note that it is considered extremely bad programming practice to ask for A when the code will quite literally die if it requires B. You should really avoid this situation.
I have two classes A and B, both inheriting from the same parent. In PHP, is there a way to make sure that class B cannot be instantiated except from within class A?
(Class B is not a child of A.)
Using debug_backtrace:
class Ancestor{}
class A extends Ancestor{
public function buildB()
{
return new B;
}
}
class B extends Ancestor{
public function __construct(){
$backtrace = debug_backtrace();
if( $backtrace[1]['class'] !== 'A' )
throw new Exception("Don't you dare!");
echo "Built successful!\n";
}
}
Try it:
//Everything ok this way:
$a = new A;
$a -> buildB();
// You will have an exception in any other case:
try{
$b = new B;
}catch(Exception $e){
echo $e -> getMessage();
}
EDIT: if you want to be sure to create B just inside A's code, you can do as well - just make buildBprivate ^^.
Yes.
How you can go about achieving it is, make the class B's constructor accept one argument. And define a method for class A that makes objects of B.
Die or throw execption if $argument == null || !($argument instanceof A).
Example code:
class X {
public $i = 0;
public function getI() {
return $i;
}
public function setI($x) {
$i = $x;
}
}
class A extends X {
public function setI($x) {
$i = $x * 2;
}
public function makeB($var){
$b = new B($var);
}
}
class B extends X {
public function __construct($a) {
if (null == $a) {
echo "no arguments given!\r\n";
//exit;
}else if (!($a instanceof A)) {
echo "disallowed\r\n";
//exit;
}else{
echo "initialized b\r\n";
}
}
public function setI($x) {
$i = $x * 3;
}
}
$a = new A();
$a->makeB();
$a->makeB(new X());
$a->makeB(&$a);
Output:
Warning: Missing argument 1 for A::makeB(), called in file.php
no arguments given!
disallowed
initialized b
You can see a demo here.
I'm not thinking of this from a php perspective, but more from the oop side...think the only way you could accomplish it is if you made B's constructor private, then exposed a static method accepting a parameter of A and an out parameter of B, then that method could privately instantiate B and return it to A through the out parameter.
//Pseudocode, language-indifferent
class A{
var _B;
public B GetMeAnInstanceOfB(){
_B=B.CreateInstanceOfB(this);
}
//alternate
public B GetMeAnotherInstanceOfB(){
_B=new B(this);
}
}
class B{
private B();
//alternate
private B(A);
static B CreateInstanceOfB(A){
return new(b);
}
}
That's really crude and probably full of potholes, but there's a stab at it. Technically, subclasses of A could still get a B, so if you sealed the class (prevented subclasses), that would close that door.
Interesting question, to be sure...
EDIT: This mod really doesn't fix the problem, but maybe(?) it's better - I've created a public constructor for B that takes an A as a parameter, and the instantiation of B now takes place only in A. The only problem is that it persists with the same problem JDelage pointed out - if I instantiate A, I can build a B...
I'm trying to create some classes and i would like to use this syntax:
$my = new My();
$my->field()->test('test');
I know how to do a $my->test('test'), it's easy - but I don't know how to add a field() attribute to make an easier comprehension of my class in my code.
I can guess it's something like a class into another class - extends - but i'm not sure about that so if you know how to do something similar.
I precise it's only for a better comprehension into my class. I mean the aim is to categorize functions in this My class.
Thank you :)
If you break your php down a bit, you will understand what is going on. For example lets make this:
$my->field()->test('test');
into this (for clarification).
$newObject = $my->field();
$newObject->test('test');
From here you can observe that the return of the method $my->field() is actually an object with another method test which you can then call. It is called method chaining and can be useful at times.
Here is a test case:
class a{
public function My(){
return new b;
}
}
class b{
public function foo(){
echo 'hello bar';
}
}
$a = new a();
$a->My()->foo();
In order to carry out an action on a method the method needs to return an object.
class a {
public function b($c){
echo $c;
return $this;
}
}
would allow
$d = new a();
$d->b("foo")->b("bar");
$d->b("foo")->b("bar")->b("far")->b("tar");
http://codepad.viper-7.com/ezvlkQ
So, I'm trying to figure out:
...?php
$object = new A();
class A
{
static public $foo = 'bar';
function displayFoo()
{
echo $this->$foo;
}
}
A::displayFoo();
A->displayFoo();
?>
About this, how many errors can you find? Can you tell me what they are in real human terms? I can't really interpret what is and what is not okay from the validator that codepad uses...
I’ve updated your code here http://codepad.viper-7.com/UaUE4g
Error 1:
echo $this->$foo;
This should read:
echo self::$foo;
.. as it is static.
Error 2:
A::displayFoo();
The method is an instance method :: is used for access to static methods.
Error 3:
A->displayFoo();
This is an error because A is undefined and if it was it should have read $A. This would be okay:
$object->displayFoo();
.. as $object is an instance of class A.
Next step, consult the manual on the topic static.
Not sure where to start. Static methods belong to the class, normal methods belong to an object, an instantiation of that class. For example, you can have:
Class A {
static public $foo = 'WOOHOOO';
static function displayFoo() {
echo self::$foo;
}
}
echo A::displayFoo();
This works because you're calling the displayFoo method belonging to class A. Or you can do this:
Class A {
public $foo = "WOOHOO";
public function displayFoo() {
echo $this->foo;
}
}
$obj = new A();
$obj->displayFoo();
Now you're creating an object based on the class of A. That object can call its methods. But the object doesn't have static methods. If you were to declare the function static, it would not be available to $obj.
You can't do:
A->displayFoo()
at all, under any circumstances, ever. The -> operator assumes an object, and A can't be an object because its not a variable.
You can read up on static class members in the manual here:
http://php.net/static
Pay close attention to the examples.
I'm getting an error that I think is because I've made some kind of mistake in a refactoring, but I can't find documentation on when $this is bound, and my error could be explained by it being bound statically.
Extra points (I can't actually give you extra points) for links to excellent documentation about this kind of thing in php.
[Edit]
The error that I'm getting is telling me that Subclass::$var doesn't exist when I do, for example, echo $this->var in a superclass. The $var exists in the subclass, though.
$this becomes available after you've called the constructor. Logically you can't use $this in a static function.
Aside from calling $this in a static function there isn't a whole lot that can go wrong timing wise as there is simply no way in PHP.
What exactly is the error you're getting? Code would useful too.
This works in PHP:
class A {
public function foo() {
echo $this->bar;
}
}
class B extends A {
public $bar = 1;
}
$b = new B;
$b->foo(); // 1
It works because of the dynamic scope resolution that PHP has (i.e.: scope is resolved at runtime as opposed to compile time). However, I'd recommend against it, because it is really a particularity of the language for one. For second, failing to declare $bar in a subclass would result in an error. I think that a class should only reference members that it is aware of.
The same code, say in C++:
class A {
public:
void foo() {
std::cout << bar;
}
};
class B : public A {
public:
int bar;
B() {
bar = 1;
}
};
...would give you a compile error (In A::foo(): 'bar' was not declared in this scope).
Yes, $this is bound dynamically, as is evidenced by the fact that the output of the following is "foo":
<?php
class Base
{
public function ecc(){
echo $this->subvar;
}
}
class Sub extends Base
{
public $subvar;
public function __construct(){
$this->subvar = 'foo';
$this->ecc();
}
}
new Sub();
?>