Hello. I have an idea which seems rather useful. I would like to know your
opinion,
Let's say we have class Rectangle and need to have class Square which will
be used in some operations. We don't need any rectangle, this must be only
square.
What if we could describe a type which is the same as another type but have
some restrictions for properties?
Something like this:
class Rectangle
{
private $x;
private $y;
private $width;
private $height;
public function __construct($x, $y, $width, $height)
{
$this->x = $x;
$this->y = $y;
$this->width = $width;
$this->height = $height;
}
}
class Square variant of Rectangle
{
public function __match()
{
if ($this->width != $this->height) {
return ['width' => 'Width and height have to be the same'];
}
return true;
}
}
function drawSquare(Square $square)
{
// ...
}
$rectangle = new Rectagle(0, 0, 10, 10);
drawSquare($rectangle);
When drawSquare() is called, the check 'instanceof' is performed. It calls
magic method __match().
If __match() does not return true, it throws an exception with the data
returned:
'Order does not match OrderForCheckout. Reason: ...'.
Technically, we don't have method __match() in $rectangle object. So it can
be static, or a proxy object can be created here.
The second variant can be extended.
We may not to inherit implementation of methods, and describe another
interface instead, for example new object can be read only.
class Square variant of Rectangle
{
public function ___match()
{
// ...
}
public function getWidth()
{
return parent::getWidth();
}
}
With some changes in syntax it can be defined in this way:
class Square variant of Rectangle
{
...
getWidth: base::getWidth;
}
This is like inheritance, but semantically differs a little.
Inheritance has vertical direction, type variants have horisontal one.
Also type variants have an access for all methods and properties of base
class, even for private.
Another example. Let's say we have an order checkout process which is
splitted into 3 steps - cart for products, date page, delivery address page.
This is not an input validation, this is a validation in business logic.
class Order
{
public $products;
public $date;
public $address;
}
class OrderForCheckout variant of Order
{
public function __match()
{
$errors = [];
if (empty($this->products)) {
$errors['products'] = 'Product list is empty';
}
if ($this->date === null) {
$errors['date'] = 'Date is not selected';
}
if (empty($this->products)) {
$errors['address'] = 'Address is not selected';
}
return (empty($errors) ? true : $errors);
}
}
public function checkout(OrderForCheckout $order)
{
...
}
$order = findCurrentOrder();
checkout($order); // if $order does not match requirements, the exception
will be thrown
'Order does not match OrderForCheckout. Reason: ...'.
Sorry, this is text for second example) I missed this moment. But I think
the idea is clear.
For manual call of __match() type casting can be used:
$orderForCheckout = (OrderForCheckout)$order;
Also this feature can be used for checking enum values or intervals.
class Value
{
public $value;
public function __construct($value)
{
$this->value = $value;
}
}
class State variant of Value
{
const ACTIVE = 1;
const INACTIVE = 2;
public function __match()
{
return in_array($this->value, [self::ACTIVE, self::INACTIVE]);
}
}
function setState(State $s)
{
...
}
setState(new State(3));
In constructions like "new State($value)" __match() can be called after
__construct().
If to add a possibility to use data types, class Value will not be needed:
class State variant of integer
{
...
public function __match()
{
return in_array($this, [self::ACTIVE, self::INACTIVE]);
}
}
setState(3);
2017-03-11 17:24 GMT+01:00 Michael Vostrikov michael.vostrikov@gmail.com:
'Order does not match OrderForCheckout. Reason: ...'.
Sorry, this is text for second example) I missed this moment. But I think
the idea is clear.For manual call of __match() type casting can be used:
$orderForCheckout = (OrderForCheckout)$order;Also this feature can be used for checking enum values or intervals.
class Value
{
public $value;public function __construct($value) { $this->value = $value; }
}
class State variant of Value
{
const ACTIVE = 1;
const INACTIVE = 2;public function __match() { return in_array($this->value, [self::ACTIVE, self::INACTIVE]); }
}
function setState(State $s)
{
...
}setState(new State(3));
In constructions like "new State($value)" __match() can be called after
__construct().If to add a possibility to use data types, class Value will not be needed:
class State variant of integer
{
...
public function __match()
{
return in_array($this, [self::ACTIVE, self::INACTIVE]);
}
}setState(3);
IMHO the real life implementations always differ, in another case, they
would be the same.
Example with Rectangle and Square IMO is an example of bad naming in this
case.
I rather want to call it Quadrangle and have one implementation or event do
the simplest inheritation.
But I may be wrong.
--
regards / pozdrawiam,
Michał Brzuchalski
about.me/brzuchal
brzuchalski.com
PHP already has horizontal inheritance. They're called traits.
How is this an improvement in anyway?
On Sat, Mar 11, 2017 at 1:36 AM, Michael Vostrikov <
michael.vostrikov@gmail.com> wrote:
Hello. I have an idea which seems rather useful. I would like to know your
opinion,Let's say we have class Rectangle and need to have class Square which will
be used in some operations. We don't need any rectangle, this must be only
square.
What if we could describe a type which is the same as another type but have
some restrictions for properties?Something like this:
class Rectangle
{
private $x;
private $y;
private $width;
private $height;public function __construct($x, $y, $width, $height) { $this->x = $x; $this->y = $y; $this->width = $width; $this->height = $height; }
}
class Square variant of Rectangle
{
public function __match()
{
if ($this->width != $this->height) {
return ['width' => 'Width and height have to be the same'];
}return true; }
}
function drawSquare(Square $square)
{
// ...
}$rectangle = new Rectagle(0, 0, 10, 10);
drawSquare($rectangle);When drawSquare() is called, the check 'instanceof' is performed. It calls
magic method __match().
If __match() does not return true, it throws an exception with the data
returned:
'Order does not match OrderForCheckout. Reason: ...'.Technically, we don't have method __match() in $rectangle object. So it can
be static, or a proxy object can be created here.The second variant can be extended.
We may not to inherit implementation of methods, and describe another
interface instead, for example new object can be read only.class Square variant of Rectangle
{
public function ___match()
{
// ...
}public function getWidth() { return parent::getWidth(); }
}
With some changes in syntax it can be defined in this way:
class Square variant of Rectangle
{
...getWidth: base::getWidth;
}
This is like inheritance, but semantically differs a little.
Inheritance has vertical direction, type variants have horisontal one.
Also type variants have an access for all methods and properties of base
class, even for private.Another example. Let's say we have an order checkout process which is
splitted into 3 steps - cart for products, date page, delivery address
page.
This is not an input validation, this is a validation in business logic.class Order
{
public $products;
public $date;
public $address;
}class OrderForCheckout variant of Order
{
public function __match()
{
$errors = [];
if (empty($this->products)) {
$errors['products'] = 'Product list is empty';
}
if ($this->date === null) {
$errors['date'] = 'Date is not selected';
}
if (empty($this->products)) {
$errors['address'] = 'Address is not selected';
}return (empty($errors) ? true : $errors); }
}
public function checkout(OrderForCheckout $order)
{
...
}$order = findCurrentOrder();
checkout($order); // if $order does not match requirements, the exception
will be thrown
Example with Rectangle and Square IMO is an example of bad naming in this
case.
I used this example because this is known problem of inheritance. Type
variants solve this problem. Square is a particular case (variant) of
Rectangle.
PHP already has horizontal inheritance. They're called traits. How is
this an improvement in anyway?
Trait is just reusable implementation. I suggest type matching. This is
extension of type hinting. It can be used in all cases where we need to
check if an object matches some criterias before continue operation. It is
a kind of defensive programming and a replacement for many 'if-throw'
constructions.
Yea, but how's that an improvement over using an interface?
On Sun, Mar 12, 2017 at 1:38 AM, Michael Vostrikov <
michael.vostrikov@gmail.com> wrote:
Example with Rectangle and Square IMO is an example of bad naming in this
case.I used this example because this is known problem of inheritance. Type
variants solve this problem. Square is a particular case (variant) of
Rectangle.PHP already has horizontal inheritance. They're called traits. How is
this an improvement in anyway?Trait is just reusable implementation. I suggest type matching. This is
extension of type hinting. It can be used in all cases where we need to
check if an object matches some criterias before continue operation. It is
a kind of defensive programming and a replacement for many 'if-throw'
constructions.
2017-03-12 11:41 GMT+05:00 Sherif Ramadan theanomaly.is@gmail.com:
Yea, but how's that an improvement over using an interface?
How can I check if an order is ready for checkout with interface? The
difference is in property values, not in presence of methods.
You could have an abstract classes implement the interface and extend from
the abstract classes.
On Sun, Mar 12, 2017 at 1:57 AM, Michael Vostrikov <
michael.vostrikov@gmail.com> wrote:
2017-03-12 11:41 GMT+05:00 Sherif Ramadan theanomaly.is@gmail.com:
Yea, but how's that an improvement over using an interface?
How can I check if an order is ready for checkout with interface? The
difference is in property values, not in presence of methods.
2017-03-12 12:03 GMT+05:00 Sherif Ramadan theanomaly.is@gmail.com:
You could have an abstract classes implement the interface and extend from
the abstract classes.
Ok, could you give an example, how to check described requirements with
interface?
Which requirements are those exactly?
On Sun, Mar 12, 2017 at 3:15 AM, Michael Vostrikov <
michael.vostrikov@gmail.com> wrote:
2017-03-12 12:03 GMT+05:00 Sherif Ramadan theanomaly.is@gmail.com:
You could have an abstract classes implement the interface and extend
from the abstract classes.Ok, could you give an example, how to check described requirements with
interface?
2017-03-12 12:19 GMT+05:00 Sherif Ramadan theanomaly.is@gmail.com:
Which requirements are those exactly?
An order should have count of products > 0 and date and address filled
before checkout procedure.
I'm not sure what that has to do with inheritance exactly or how it
pertains to this discussion. This is an implementation detail.
On Sun, Mar 12, 2017 at 3:47 AM, Michael Vostrikov <
michael.vostrikov@gmail.com> wrote:
2017-03-12 12:19 GMT+05:00 Sherif Ramadan theanomaly.is@gmail.com:
Which requirements are those exactly?
An order should have count of products > 0 and date and address filled
before checkout procedure.
2017-03-12 13:03 GMT+05:00 Sherif Ramadan theanomaly.is@gmail.com:
how it pertains to this discussion
This is example of type matching from my first message.
I'm not sure what that has to do with inheritance
Yes, this is not related with inheritance. But order can be ready for
checkout or can not. This is a variant of valid object state. If we could
have a tool to describe that and check later, it would be useful.
If the problem you're trying to solve pertains to object state that I have
no idea how this proposal hopes to achieve that. You can readily control
object state in PHP without the need for declarative types (e.g. magic
getters/setters). Not seeing how this proposal improves or even achieves
such a thing. I think you're trying desperately to find a problem that is
fitting of the proposal whereas all real-world problems that exist under
this domain are already solved problems.
On Sun, Mar 12, 2017 at 4:17 AM, Michael Vostrikov <
michael.vostrikov@gmail.com> wrote:
2017-03-12 13:03 GMT+05:00 Sherif Ramadan theanomaly.is@gmail.com:
how it pertains to this discussion
This is example of type matching from my first message.
I'm not sure what that has to do with inheritance
Yes, this is not related with inheritance. But order can be ready for
checkout or can not. This is a variant of valid object state. If we could
have a tool to describe that and check later, it would be useful.
2017-03-12 13:58 GMT+05:00 Sherif Ramadan theanomaly.is@gmail.com:
I think you're trying desperately to find a problem that is fitting of
the proposal
Checks in business logic are popular task.
If the problem you're trying to solve pertains to object state that I
have no idea how this proposal hopes to achieve that. You can readily
control object state in PHP without the need for declarative types (e.g.
magic getters/setters)
I described in first message the way how the proposal can help with this.
There is no magic getters/setters there.
Not seeing how this proposal improves or even achieves such a thing.
Now we need to write in business logic the following:
function checkout(Order $order)
{
if (count($order->products) > 0) {
throw new SomeException1();
}
if ($order->date === null) {
throw new SomeException2();
}
if ($order->address === null) {
throw new SomeException3();
}
// checkout steps
...
someActionWithOrderForCheckout($order);
...
}
function someActionWithOrderForCheckout(Order $order)
{
if (count($order->products) > 0) {
...
}
if ()
...
}
Of course, we can move all checks to some function like
'ensureOrderIsReadyForCheckout()' and call it everywhere manually.
But this is the same as call is_integer()
manually instead of type hinting.
Now we need to write in business logic the following:
function checkout(Order $order)
{
if (count($order->products) > 0) {
throw new SomeException1();
}
if ($order->date === null) {
throw new SomeException2();
}
if ($order->address === null) {
throw new SomeException3();
}// checkout steps ... someActionWithOrderForCheckout($order); ...
}
function someActionWithOrderForCheckout(Order $order)
{
if (count($order->products) > 0) {
...
}
if ()
...
}Of course, we can move all checks to some function like
'ensureOrderIsReadyForCheckout()' and call it everywhere manually.
But this is the same as callis_integer()
manually instead of type hinting.
The problem you are facing is that you are dealing with an anemic domain
object that does not enforce its own invariants. Properly applying OOD
principles would remedy all your problems. However, you do not require
new features to do that.
--
Richard "Fleshgrinder" Fussenegger
2017-03-12 14:58 GMT+05:00 Fleshgrinder php@fleshgrinder.com:
The problem you are facing is that you are dealing with an anemic domain
object that does not enforce its own invariants.
Incomlplete order with date and address not set yet is a valid state of
order.
Also, there are many cases when logic which includes many objects is placed
in a service and not in any of that objects.
However, you do not require new features to do that.
I don't tell that we cannot make that with current features. I suggest a
way to do that more easy. This is like type hinting. We can check types
manually by calling functions like is_integer()
or get_class()
, but we
don't have a question why we need to have type hinting in language.
2017-03-12 14:58 GMT+05:00 Fleshgrinder php@fleshgrinder.com:
The problem you are facing is that you are dealing with an anemic domain
object that does not enforce its own invariants.Incomlplete order with date and address not set yet is a valid state of
order.
Also, there are many cases when logic which includes many objects is placed
in a service and not in any of that objects.
Sure, but you should still not have an anemic domain. Any object needs
to ensure its own invariants, that's nothing another service should do.
You are clearly dealing with two kinds of orders, hence, create two
kinds of orders. IncompleteOrder
is the one without date, address, and
probably even products. You directly named it as such. Then you have
ProcessableOrder
where this is impossible. BAM all problems solved.
2017-03-12 14:58 GMT+05:00 Fleshgrinder php@fleshgrinder.com:
However, you do not require new features to do that.
I don't tell that we cannot make that with current features. I suggest a
way to do that more easy. This is like type hinting. We can check types
manually by calling functions likeis_integer()
orget_class()
, but we
don't have a question why we need to have type hinting in language.
The problem is that your proposal is meant to solve problems that are
already solved in a way that is not really understood by anyone so far.
--
Richard "Fleshgrinder" Fussenegger
$rectangle = new Rectangle(0, 0, 10, 10);
drawSquare($rectangle);When drawSquare() is called, the check 'instanceof' is performed. It calls
magic method __match().
If __match() does not return true, it throws an exception with the data
returned:
My problem here is with the reason for needing a different class for
'Square' when $rectangle->is_square() is a simple additional check on a
single Rectangle class. drawSquare() seems redundant when
$rectangle->draw() does the same job ... a lot of duplicate code for
little gain? My problem I think is 'instanceof' is being used
incorrectly here.
'Order does not match OrderForCheckout. Reason: ...'.
The class is 'Order' which in my book will be a variable list of
'LineItem' and each line item will have a status such as is_instock().
The Order status of is_shipable() flags an order that is ready for
shipment which will produce an answer of yes, partial or no.
Just as you don't need to change Rectangle->Square just because you want
to draw a square with a set of numbers which started as a Rectangle, you
don't want to change the class from Order to OrderForCheckout. The base
order simple has a set of constraints which must be met before is_ready
can apply and is_billable will flag if you only charge for a shipment,
or take a full payment with order. LineItem has a check on 'backorder'
to validate if it's allowed to add items which are out of stock.
While I think I can see the logic behind describing these as different
types of object I think it is the same mistake as strictly enforcing
'int' when the raw data you have is a string of numbers. And just
because you know you have a number for the quantity to buy you still
need to check that against the stock level and handle it differently if
there is not sufficient stock. Trying to create 'type's for all the
variants of the object is just wrong? int_instock, int_minorder,
int_backorder, int_special_production and so on as the types of LineItem
so 'instanceof' will work for you?
--
Lester Caine - G8HFL
Contact - http://lsces.co.uk/wiki/?page=contact
L.S.Caine Electronic Services - http://lsces.co.uk
EnquirySolve - http://enquirysolve.com/
Model Engineers Digital Workshop - http://medw.co.uk
Rainbow Digital Media - http://rainbowdigitalmedia.co.uk
2017-03-12 14:14 GMT+05:00 Lester Caine lester@lsces.co.uk:
My problem here is with the reason for needing a different class for
'Square' when $rectangle->is_square() is a simple additional check on a
single Rectangle class.
Yes. And we have to call it in all operations with Square manually, and
throw exceptions/return errors manually.
drawSquare() seems redundant when $rectangle->draw() does the same job
This is just example of external function with type hinting. And I'm not
sure that models should know about device contexts, canvases, pixels and
other details of presentation layer.
Trying to create 'type's for all the variants of the object is just
wrong? int_instock, int_minorder, int_backorder, int_special_production and
so on as the types of LineItem so 'instanceof' will work for you?
I don't need to create a separate type for every characteristic. I need to
create a type for some important operations, which will contain all
required restictions of object state and which I could just write in all
functions that work with this state.
Hi Michael,
On Sat, Mar 11, 2017 at 3:36 PM, Michael Vostrikov <
michael.vostrikov@gmail.com> wrote:
class Square variant of Rectangle
{
public function __match()
{
if ($this->width != $this->height) {
return ['width' => 'Width and height have to be the same'];
}return true; }
}
DbC allows this kind of validation at development time.
I suppose you would like to check requirement at runtime always.
It would be nice to have feature, but I think
something like __requrie()
is better name for the method.
IMO, C# like getter/setter is better though.
Regards,
--
Yasuo Ohgaki
yohgaki@ohgaki.net
DbC allows this kind of validation at development time.
I suppose you would like to check requirement at runtime always.
It would be nice to have feature, but I thinksomething like __requrie()
is better name for the method.
IMO, C# like getter/setter is better though.
Hey Yasuo! :)
Design by Contract is a nice thing, and you know that I would love to
see it as part of the language. However, it is not really the solution
to the problem that is being described here, since it is a valid state
for an order to be empty. The stated Square-Rectangle example is a
different beast, and there are many solutions to it. I probably would
argue that Rectangle needs to extend Square and not the other way.
Square has an extended functionality compared to Rectangle while being
fully compatible.
DbC would still be nice and would allow us to add real invariant, pre-,
and post-conditions. I, as you might remember, would not go for a magic
method but rather an extended block, like we see it for if-else or
try-catch:
class C {}
invariant {} // one assert per line
function f() {}
requires {} // pre-conditions
ensures {} // post-conditions
--
Richard "Fleshgrinder" Fussenegger
2017-03-12 15:33 GMT+05:00 Yasuo Ohgaki yohgaki@ohgaki.net:
DbC allows this kind of validation at development time.
I suppose you would like to check requirement at runtime always.
Yes, DbC from here https://wiki.php.net/rfc/dbc2 describes similar things.
This is good idea, but I tell more about checks which cannot be removed
from code. Types which meet some requirements looks more closer to business
logic terms than constructions like if-throw or
require($order->isReadyForSomething()).
2017-03-12 15:35 GMT+05:00 Fleshgrinder php@fleshgrinder.com:
IncompleteOrder
is the one without date, address, and
probably even products. You directly named it as such. Then you have
ProcessableOrder
where this is impossible
Yes, this is Order and OrderForCheckout in my example. But they should not
be descendants of base class or each other. Because allowed class states
are not descendants of that class.
BAM all problems solved.
Yeah, now we have:
base Order
IncompleteOrder extends Order
ProcessableOrder extends Order
PaidOrder extends Order // or ProcessableOrder?
and later could get:
WholesaleOrder extends Order
with a question how to extend classes in new branch.
Also the problem is how to use this tree in relations.
There is class OrderItem with $order property.
There is class Customer with $orders property.
What classes should have these properties? Every time different?
This is a part of another problem that we need to decide what exact class
should be created here or there before calling a function which uses it.
With type variants (hm, or invariants) it could be:
Order
ProcessableOrder variant of Order
PaidOrder variant of Order
WholesaleOrder variant of Order
And everywhere we can create and use objects with class Order, and only in
some functions they will be considered as processable or not.
2017-03-12 15:35 GMT+05:00 Fleshgrinder php@fleshgrinder.com:
IncompleteOrder
is the one without date, address, and
probably even products. You directly named it as such. Then you have
ProcessableOrder
where this is impossibleYes, this is Order and OrderForCheckout in my example. But they should not
be descendants of base class or each other. Because allowed class states
are not descendants of that class.BAM all problems solved.
Yeah, now we have:
base Order
IncompleteOrder extends Order
ProcessableOrder extends Order
PaidOrder extends Order // or ProcessableOrder?and later could get:
WholesaleOrder extends Orderwith a question how to extend classes in new branch.
Also the problem is how to use this tree in relations.
There is class OrderItem with $order property.
There is class Customer with $orders property.
What classes should have these properties? Every time different?This is a part of another problem that we need to decide what exact class
should be created here or there before calling a function which uses it.With type variants (hm, or invariants) it could be:
Order
ProcessableOrder variant of Order
PaidOrder variant of Order
WholesaleOrder variant of OrderAnd everywhere we can create and use objects with class Order, and only in
some functions they will be considered as processable or not.
Post this on Stackoverflow and I'll give you some answers and possible
approaches. ;) You are clearly struggling with architecture and design,
but you are definitely not missing language constructs here.
--
Richard "Fleshgrinder" Fussenegger
2017-03-12 18:54 GMT+05:00 Fleshgrinder php@fleshgrinder.com:
Post this on Stackoverflow and I'll give you some answers and possible
approaches. ;) You are clearly struggling with architecture and design,
but you are definitely not missing language constructs here.--
Richard "Fleshgrinder" Fussenegger
No, thanks) I don't have real problem. I know some problems with usual
inheritance and try to suggest the tool to solve them. Problems which are
mostly kinds of Rectangle-Square problem, and where is some restrictions in
derived types.
No, thanks) I don't have real problem. I know some problems with usual
inheritance and try to suggest the tool to solve them. Problems which are
mostly kinds of Rectangle-Square problem, and where is some restrictions in
derived types.
As I said already, there is no problem if you just change the direction
of the inheritance.
class Square {
private $x;
private $y;
private $w;
public function __construct(int $x, int $y, int $w) {
$this->x = $x;
$this->y = $y;
$this->w = $w;
}
public function draw(Canvas $canvas): void { }
}
class Rectangle extends Square {
private $h;
public function __construct(int $x, int $y, int $w, int $h) {
parent::__construct($x, $y, $w);
$this->height = $h;
}
public function draw(Canvas $canvas): void { }
}
If you want to ensure that you always get a Square if width and height
match, no problem either.
class Square {
private $x;
private $y;
private $w;
private $h;
final protected function __construct(
int $x, int $y, int $w, int $h
) {
$this->x = $x;
$this->y = $y;
$this->w = $w;
$this->h = $h;
}
public static function new(int $x, int $y, int $w): self {
return new self($x, $y, $w, $w);
}
public function draw(Canvas $canvas): void { }
}
class Rectangle extends Square {
public static function new(
int $x, int $y, int $w, ?int $h = null
): parent {
if ($h === null || $w === $h) {
return new parent($x, $y, $w, $w);
}
return new self($x, $y, $w, $h);
}
}
Added bonus here is the fact that we disabled the possibility for
multiple constructor invocations, and are enforcing constructor argument
invariants (which PHP does not).
--
Richard "Fleshgrinder" Fussenegger
Hi Michael,
IMO, C# like getter/setter is better though.
http://stackoverflow.com/questions/11159438/looking-
for-a-short-simple-example-of-getters-setters-in-c-sharp
I pasted wrong URL. This URL has better example code.
https://msdn.microsoft.com/en-us/library/w86s7x04.aspx
While DbC is nice, but checks are only performed on dev environment for
maximum performance and acceptable safety. Therefore, developers must
implement mandatory validations at trust boundaries to ensure software
safety.
i.e. Code correctness and security. Your proposal is useful for this.
Please note that, with DbC, caller has responsibility to make correct calls
that
follow contracts. e.g. Caller must use sane parameters for callee. With
this design,
basic objects/functions, that may execute validation code repetitively, can
safely
omit validations for maximum performance as long as contracts are
maintained.
I'm not against to have method/feature that validates object, but it would
be
better to implement DbC support, then runtime object validation support.
Otherwise,
users would design poor performance objects that execute validation code
repetitively.
Regards,
--
Yasuo Ohgaki
yohgaki@ohgaki.net
2017-03-12 23:01 GMT+05:00 Fleshgrinder php@fleshgrinder.com:
As I said already, there is no problem if you just change the direction
of the inheritance.
Ok, how to inherit Rectangle, Square, Rhomb, all of which are
Parallelogram? In your example Rectangle knows restrictions of Square and
any Rectangle is instance of Square. It does not match domain model.
2017-03-13 1:40 GMT+05:00 Yasuo Ohgaki yohgaki@ohgaki.net:
I pasted wrong URL. This URL has better example code.
https://msdn.microsoft.com/en-us/library/w86s7x04.aspx
Getters/setters is a good feature, I'd like them to be in PHP, but they
should be placed in some classes. What are these classes? We still cannot
use all squares as rectangles and some rectangles as squares without
questions. And if we already have one $rectangle with w == h, we cannot
just use it as square, we must create new object based on $rectangle data.