This is my first time having this problem and I hope that you can give me some explanation or some impetus to solve it.
I wrote this code here:
class Foo
{
public function __construct()
{
$this->bar = New Bar();
}
}
class Bar
{
public function __construct()
{
$this->foo = New Foo();
}
}
$foo = New Foo();
This code throwns following error:
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 262144 bytes)
How can I let the two classes communicate with each other without getting this error?
Edit:
As requested, I'll go into a little more detail. As an example, I have written two classes that are forced to communicate with each other, similar to my current project:
class UserStatusController
{
public function __construct()
{
$this->couponController = New CouponController();
}
private $badStatus = "blocked";
public function hasBadStatus(int $id): bool
{
$user = User::where(['id' => $id])->get();
return $user->status == self::$badStatus ? true : false;
}
public function actualizeStatus(int $id, string $status): bool
{
if ($status == self::$badStatus) {
$this->couponController->deleteCoupon();
return false;
}
$user = User::where(['id' => $id])->update(['status' => $status]);
$this->couponController->createCoupon();
return true;
}
}
class CouponController
{
public function __construct()
{
$this->userStatusController = New UserStatusController();
}
public function createCoupon(): bool
{
if ($this->userStatusController->hasBadStatus()) { return false; }
// create coupon ...
}
public function deleteCoupon(): bool
{
// delete coupon ...
}
}
Since the two classes each have information that the other class needs, they have to somehow exchange data. In the example above there is an infinity loop.
So the question is, what is the most common way of letting these two classes talk to each other?
In your code, you initiate New Bar(); in class Foo, and then initiate New Foo() in class Bar, which initiates New Bar() and so on.
The code below returns bool(true) which I presume is what you at trying to achieve.
<?php
class Foo
{
public function foo1()
{
return true;
}
}
class Bar
{
public function __construct()
{
$this->foo = New Foo();
}
}
$foo = New Foo();
var_dump( $foo->foo1() );
If you need something else please edit your question and be more specific. On the other hand, if you ammend the code like this:
class Foo
{
public function foo1()
{
return true;
}
}
class Bar
{
public function __construct()
{
$this->foo = New Foo();
return $this->foo;
}
}
$foo = New Bar();
var_dump($foo);
the result is object(Bar)#1 (1) { ["foo"]=> object(Foo)#2 (0) { } }
Also, if the 2 functions are on the same file, you don't need to have another class. If they have to be in separate files, you can write class bar extends Foo. There are a lot of OOP courses and free videos explaining classes, functions and so on.
Related
I am trying to display an array of messages at the end of my PHP class. My message handler is working, but only if I "add_message" from within the main parent class and not if I call this function from within a child class. Sorry if this is vague but was not sure how to word the question.
TLDR; How can I add a message from within class Example?
MAIN PARENT CLASS
class Init {
public function __construct() {
$this->load_dependencies();
$this->add_messages();
$this->add_msg_from_instance();
}
private function load_dependencies() {
require_once ROOT . 'classes/class-messages.php';
require_once ROOT . 'classes/class-example.php';
}
public function add_messages() {
$this->messages = new Message_Handler();
$this->messages->add_message( 'hello world' );
}
// I Would like to add a message from within this instance....
public function add_msg_from_instance() {
$example = new Example();
$example->fire_instance();
}
public function run() {
$this->messages->display_messages();
}
}
MESSAGE HANDLER
class Message_Handler {
public function __construct() {
$this->messages = array();
}
public function add_message( $msg ) {
$this->messages = $this->add( $this->messages, $msg );
}
private function add( $messages, $msg ) {
$messages[] = $msg;
return $messages;
}
// Final Function - Should display array of all messages
public function display_messages() {
var_dump( $this->messages );
}
}
EXAMPLE CLASS
class Example {
public function fire_instance() {
$this->messages = new Message_Handler();
$this->messages->add_message( 'Hello Universe!' ); // This message is NOT being displayed...
}
}
Because you want to keep the messages around different object, you should pass the object or use a static variable.
I would use a static variable like so:
class Init {
public function __construct() {
$this->load_dependencies();
$this->add_messages();
$this->add_msg_from_instance();
}
private function load_dependencies() {
require_once ROOT . 'classes/class-messages.php';
require_once ROOT . 'classes/class-example.php';
}
public function add_messages() {
// renamed the message handler variable for clarity
$this->message_handler = new Message_Handler();
$this->message_handler->add_message( 'hello world' );
}
// I Would like to add a message from within this instance....
public function add_msg_from_instance() {
$example = new Example();
$example->fire_instance();
}
public function run() {
$this->message_handler->display_messages();
}
}
class Message_Handler {
// use a static var to remember the messages over all objects
public static $_messages = array();
// add message to static
public function add_message( $msg ) {
self::$_messages[] = $msg;
}
// Final Function - Should display array of all messages
public function display_messages() {
var_dump( self::$_messages );
}
}
class Example {
public function fire_instance() {
// new object, same static array
$message_handler = new Message_Handler();
$message_handler->add_message( 'Hello Universe!' );
}
}
// testing...
new Init();
new Init();
$init = new Init();
$init->add_msg_from_instance();
$init->add_msg_from_instance();
$init->add_msg_from_instance();
$init->run();
Although global variables might not be the best design decision, you have at least two approaches to achieve what you want:
Use singleton.
Nowadays it is considered anti-pattern, but it is the simplest way: make message handler a singleton:
class MessageHandler
{
private static $instance;
private $messages = [];
public static function instance(): self
{
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct()
{
}
public function addMessage($message): self
{
$this->messages[] = $message;
return $this;
}
public function messages(): array
{
return $this->messages;
}
}
Then instead of creating a new instance of MessageHandler access it via the static method MessageHandler::instance(). Here is a demo.
Use DI container to inject the same instance (that is created once and held in the container) into all instances that need to access it. This approach is more preferable, but harder to implement in the project where there is no DI container available in the first place.
I'm new to the OOP model of PHP and encountered a problem recently.
When Object B is thrown in Object A and calls a function of B, is it possible to get Object A inside the function of B?
Consider the following code example:
$test = new A();
class A
{
public function __construct () {
$arg = "something";
try{
throw new B($arg);
}
catch (B $e) {
$e->bar();
}
}
public function foo($arg){
//do something
}
}
class B extends Exception
{
public $arg;
public function __construct ($arg) {
$this->arg = $arg;
}
public function bar(){
// do something
// .....
// this is not correct, $this is not object A
// so how do i do this?
$this->foo($arg);
}
}
You can pass a caller object into a constructor:
throw new B($this);
Your B constructor will place it into $arg:
public $arg; // better call it $caller or somewhat
public function __construct ($arg) {
$this->arg = $arg;
}
Then, in a method of B you can access it:
public function bar(){
$this->arg->foo(""); // pass an argument, which is expected at function foo($arg){}
}
Here is the working IDEOne demo.
Also, #Sumurai8 has implemented a good PHPFiddle demo. It extends your constructor so that it passes both argument and caller.
It is not the best approach, as you assume that Exception B is thrown from the class that have method foo, which may not alway be the case.
I would recommend to keep it simple:
$test = new A();
class A
{
public function __construct () {
$arg = "something";
try{
throw new B($arg);
}
catch (B $e) {
$e->bar();
$this->foo($arg);
}
}
public function foo($arg){
//do something
}
}
class B extends Exception
{
public $arg;
public function __construct ($arg) {
$this->arg = $arg;
}
public function bar(){
// do something
// .....
// this is correct now
}
}
I'm wondering if its possible to switch the visibility in PHP. Let me demonstrate:
class One {
function __construct($id){
if(is_numeric($id)){
//Test function becomes public instead of private.
}
}
private function test(){
//This is a private function but if $id is numeric this is a public function
}
}
Is such thing even possible?
I would use an abstract class with two implementing classes: One for numeric and one for non-numeric:
abstract class One {
static function generate($id) {
return is_numeric($id) ? new OneNumeric($id) : new OneNonNumeric($id);
}
private function __construct($id) {
$this->id = $id;
}
}
class OneNumeric extends One {
private function test() {
}
}
class OneNonNumeric extends One {
public function test() {
}
}
$numeric = One::generate(5);
$non_numeric = One::generate('not a number');
$non_numeric->test(); //works
$numeric->test(); //fatal error
It can be faked up to a point with magic methods:
<?php
class One {
private $test_is_public = false;
function __construct($id){
if(is_numeric($id)){
$this->test_is_public = true;
}
}
private function test(){
echo "test() was called\n";
}
public function __call($name, $arguments){
if( $name=='test' && $this->test_is_public ){
return $this->test();
}else{
throw new LogicException("Method $name() does not exist or is not public\n");
}
}
}
echo "Test should be public:\n";
$numeric = new One('123e20');
$numeric->test();
echo "Test should be private:\n";
$non_numeric = new One('foo');
$non_numeric->test();
I haven't thought about the side effects. Probably, it's only useful as mere proof of concept.
so I am new in the world of object oriented programming and I am currently facing this problem (everything is described in the code):
<?php
class MyClass {
// Nothing important here
}
class MyAnotherClass {
protected $className;
public function __construct($className){
$this->className = $className;
}
public function problematicFunction({$this->className} $object){
// So, here I obligatorily want an $object of
// dynamic type/class "$this->className"
// but it don't works like this...
}
}
$object = new MyClass;
$another_object = new MyAnotherClass('MyClass');
$another_object->problematicFunction($object);
?>
Can anyone help me ?
Thanks, Maxime (from France : sorry for my english)
What you need is
public function problematicFunction($object) {
if ($object instanceof $this->className) {
// Do your stuff
} else {
throw new InvalidArgumentException("YOur error Message");
}
}
Try like this
class MyClass {
// Nothing important here
public function test(){
echo 'Test MyClass';
}
}
class MyAnotherClass {
protected $className;
public function __construct($className){
$this->className = $className;
}
public function problematicFunction($object){
if($object instanceof $this->className)
{
$object->test();
}
}
}
$object = new MyClass;
$another_object = new MyAnotherClass('MyClass');
$another_object->problematicFunction($object);
That's called type hinting and what you want to do is just not supported.
If all those dynamic class names have something in common (e.g., they're different implementations for certain feature) you probably want to define a base (maybe abstract) class or an interface and use that common ancestor as type hint:
<?php
interface iDatabase{
public function __contruct($url, $username, $password);
public function execute($sql, $params);
public function close();
}
class MyClass implements iDatabase{
public function __contruct($url, $username, $password){
}
public function execute($sql, $params){
}
public function close(){
}
}
class MyAnotherClass {
protected $className;
public function __construct($className){
$this->className = $className;
}
public function problematicFunction(iDatabase $object){
}
}
Otherwise, just move the check to within problematicFunction() body, as other answers explain.
Please look at the following code snipped
class A
{
function __get($name)
{
if ($name == 'service') {
return new Proxy($this);
}
}
function render()
{
echo 'Rendering A class : ' . $this->service->get('title');
}
protected function resourceFile()
{
return 'A.res';
}
}
class B extends A
{
protected function resourceFile()
{
return 'B.res';
}
function render()
{
parent::render();
echo 'Rendering B class : ' . $this->service->get('title');
}
}
class Proxy
{
private $mSite = null;
public function __construct($site)
{
$this->mSite = $site;
}
public function get($key)
{
// problem here
}
}
// in the main script
$obj = new B();
$obj->render();
Question is: in method 'get' of class 'Proxy', how I extract the corresponding resource file name (resourceFile returns the name) by using only $mSite (object pointer)?
What about:
public function get($key)
{
$file = $this->mSite->resourceFile();
}
But this requires A::resourceFile() to be public otherwise you cannot access the method from outside the object scope - that's what access modifiers have been designed for.
EDIT:
OK - now I think I do understand, what you want to achieve. The following example should demonstrate the desired behavior:
class A
{
private function _method()
{
return 'A';
}
public function render()
{
echo $this->_method();
}
}
class B extends A
{
private function _method()
{
return 'B';
}
public function render()
{
parent::render();
echo $this->_method();
}
}
$b = new B();
$b->render(); // outputs AB
But if you ask me - I think you should think about your design as the solution seems somewhat hacky and hard to understand for someone looking at the code.