Jump to content

Accessing global in constructor or parent class


jbonnett

Recommended Posts

Hi All,

I am trying to create an MVC login script, I have a couple of problems first I'll give you a list of necessary classes, functions and or description:

 

Init.php

  • Loads all core classes to variable called core, and calls app.php

App.php

  • Parses the URL and gets the controller for the particular page.

Controller.php

  • Function model() - loads a new model.
  • Function view() - loads a new view.
  • Variable view - holds all view data in an array.
  • Variable core - holds all instances of core classes (from init). 

LoginController.php - extends Controller.php

  • Loads login model.
  • Does checks by calling functions from the login model.
  • Calls the view in the deconstructor.

LoginModel.php

  • Checks login data.
  • Returns errors via the inherited view variable from Controller.

Now lets say I want to set the core variable, it won't let me in Controller.php... I tried this:

protected $core = array();

public __construtor() {
    global $core;
    $this->core = $core;
}

It didn't work, I tried adding the constructor in the LoginModel.php keeping the core variable in Controller. The only way I got it to work was by doing this:

private function core($class) {
	global $core;
	$this->core = $core;
	return $this->core[$class];
}

Which I have to do with all the controllers.

 

The second problem I was having is using the view variable from Controller.php in the LoginModel.php, as I have called the LoginModel.php in the LoginController.php the model should inherit the view variable, I've even tried adding "extends Controller" to the LoginModel.php with no joy.

 

Please help. 

Link to comment
Share on other sites

While you're still in the design stage, you might want to rethink your "super object" strategy, but if you insist to proceed, the proper technique for allowing a class to use such an object would be to inject it through the constructor. So at some point you are creating a new Controller, and you would just pass the core variable as a parameter. Also, unless just a typo here in the forum, you'll want to make sure your constructor method is named correctly. __constructor not __construtor

Link to comment
Share on other sites

I agree with sKunKbad - stay away from global variables. If you're extending classes, make the parent class property protected and call it from the child class or inject the property through the constructor of the secondary class.

Link to comment
Share on other sites

Yeah don't worry about the typo, I tried to pass it through the constructor too... The problems is if I try using the global with any of the constructors that need the core classes, it will not work. I just get an empty array. All the modifiers are as they should be.

Edited by jbonnett
Link to comment
Share on other sites

Sorry - it's early and all, but I'm not following that last comment (other than the typo bit). Post some code and more detail on the expected and actual results and we can get you moving in the right direction.

Link to comment
Share on other sites

As a side note I want to point out that MVC does not mean create a Model class, a Controller class, and a View class. It means separation of concerns, where the important bits are Model (Business Logic) and View (Presentation Logic). The Controller is the part that binds these two together.

 

A simple (W)MVC example would be a contact page:

 

// contact.php

if (isset($_POST['submit'])) {
  mail('hello@some.website', $_POST['subject'], $_POST['message']);
}

include 'views/contact.html';
Believe it or not, but this is really an (W)MVC implementation.

 

Where:

- contact.php -- is the controller (model and view are unaware of each other, yet together they achieve a specific goal, contacting the owner)

- mail() -- is the model (hiding how mailing works and providing a simple interface)

- views/contact.html -- is the view (hiding the interface how the user will enter the required data)

- Apache -- is the frontController (like your App.php, translate a route to a controller)

 

It's important that the model is unaware of the view and the controller otherwise it would severely limit it's re-use.

 

Your LoginModel is also not correct because it violates the Single Responsibility Principle. It finds a user based on user and pass, and it stores a session cookie. You'll also have to duplicate the "find a user based on user and pass" every time you need it thus violating the Don't Repeat Yourself principle.

 

class UserMapper .. {
  private $pdo;
  
  function __construct(PDO $pdo) {
    $this->pdo = $pdo;
  }
  
  function findByNameAndPassword($username, $password) {
     // implementation
  }
}

class Session .. {
  function set($key, $value, $lifetime) {
    // implementation
  }
  
  function get($key, $default = null) {
    // implementation
  }
}

class LoginService {
  private $userMapper;
  private $session;
  
  function login($username, $password) {
    // $user = $this->userMapper->findByNameAndPassword($username, $password);
    // if (null !== $user) {
    //   $this->session->set('loggedin', true, 86400);
    // }
  }

  function isLoggedIn() {
    return $this->session->get('loggedin', false);
  }
}
As an example. You would use the LoginService in your controller as it hides how a user is logged in and is completely re-usable in another project if needed. Controller and View are considered to be project specific and thus (mostly) throw-away-code. The Model however not so much.

 

This kind of programming will help keep your controllers thin and your (model) code re-usable.

Edited by ignace
  • Like 1
Link to comment
Share on other sites

  • 4 weeks later...

Here's a better idea of what the problem is, init calls router and router extends init, the thing is I want to keep the public vars for use in router but the "extends" creates a new instance by the looks of it...

 

Init.php

<?php

    /**
     * Created by PhpStorm.
     * User: Jamie
     * Date: 27-Jun-15
     * Time: 10:44 AM
     */

    class Init {

        public $root;
        public $directorySeparator;

        public function __construct() {
            $this->root = $_SERVER["DOCUMENT_ROOT"];
            $this->directorySeparator = DIRECTORY_SEPARATOR;

            set_error_handler(array($this, "ErrorHandler"));

            require_once($this->root . $this->directorySeparator . "Private" . $this->directorySeparator . "Router.php");
            new Router();
        }

        public function ErrorHandler($errno, $errstr, $errfile, $errline) {
            echo "<b>Custom Error:</b> [" . $errno . "] " . $errstr . "<br />";
            echo " Error on line " . $errline . " in line " . $errfile . ".";
        }

    };

?>

Router.php

<?php

    /**
     * Created by PhpStorm.
     * User: Jamie
     * Date: 27-Jun-15
     * Time: 11:14 AM
     */

    class Router extends Init {

        protected $controller = "home";
        protected $method = "index";
        protected $perams = array();

        public function __construct() {
            $url = $this->parseURL();

            if(file_exists($this->root . "Private" . $this->directorySeparator . "Controllers" . $this->directorySeparator . $url[0] . ".php")) {
                $this->controller = $url[0];
                unset($url[0]);
            }
            require_once($this->root . "Private" . $this->directorySeparator . "Controllers" . $this->directorySeparator . $this->controller . ".php");
            $this->controller = new $this->controller;

            if(isset($url[1])) {
                if(method_exists($this->controller, $url[1])) {
                    $this->method = $url[1];
                    unset($url[1]);
                }
            }

            $this->perams = $url ? array_values($url) : array();
            call_user_func_array(array($this->controller, $this->method), $this->perams);
        }

        public function parseURL() {
            if(isset($_GET["url"])) {
                return explode("/", filter_var(rtrim($_GET["url"], "/"), FILTER_SANITIZE_URL));
            }
        }

    };

?>
Link to comment
Share on other sites

Don't instantiate Router from Init. Route extends Init, so all the functionality of Init is available to Router. You should be instantiating a Router object, not an Init object. In your Router::__construct() method, call

parent::__construct();

This will fire the Init object's constructor, and you'll get access to $root and $directorySeparator.

Link to comment
Share on other sites

Don't instantiate Router from Init. Route extends Init, so all the functionality of Init is available to Router. You should be instantiating a Router object, not an Init object. In your Router::__construct() method, call

parent::__construct();

This will fire the Init object's constructor, and you'll get access to $root and $directorySeparator.

 

I want to be able to call init though... Init will end up with a lot more stuff yet.

Edited by jbonnett
Link to comment
Share on other sites

I want to be able to call init though... Init will end up with a lot more stuff yet.

 

You'll be able to call anything protected or public in Init() from within Router(). If you don't need to do anything different with a method in the Router() class, don't define it in the Router() class and the call will bubble up to Init() automatically. For instance:

class ParentClass{
/**
 *	Runs because the constructor is called on the child class and not intercepted.
 */
	public function __construct(){
		print("<p>This is ParentClass() calling!</p>");
	}
/**
 *	This is public and can be called from anywhere
 */
	public function doStuff(){
		print("<p>Now ParentClass() is doing stuff!</p>");
	}
/**
 *	This is protected, so can only be called from the child class. However,
 *	we're doing more with this method by adding another line of output after
 *	calling this method from the child class.
 */
	protected function polymorphismAtWork(){
		print("<p>ParentClass() says 'hi!'</p>");
	}
/**
 *	Again, this is protected and can only be called from within a child class.
 */
	protected function protectedFunction(){
		print("<p>This method is protected!</p>");
	}
/**
 *	Not even a child class can call this method.
 */
	private function privateFunction(){
		print("<p>Nope. No access, thanks</p>");
	}
}

class ChildClass extends ParentClass{
/**
 *	This is public and can be called from anywhere, yet has nothing to do with the parent class.
 */
	public function doOtherStuff(){
		print("<p>This is ChildClass() doing other stuff!</p>");
	}
/**
 *	This adds additional functionality to the parent polymorphismAtWork() method.
 *	It can completely replace the parent class method, but here we're doing some
 *	work and passing the call to the parent version for it's own output.
 */
	public function polymorphismAtWork(){
		parent::polymorphismAtWork();
		print("<p>ChildClass intercepts and says 'hello...'</p>");
	}
/**
 *	Even though the child method is public, the parent is private. This will throw an
 *	error.
 */
	public function tryToAccessPrivateMethod(){
		parent::privateFunction();
	}
}

$inst = new ChildClass();		// This is ParentClass() calling!
$inst->doStuff();			// Now ParentClass() is doing stuff!
$inst->doOtherStuff();			// This is ChildClass() doing other stuff!
$inst->polymorphismAtWork();		// ParentClass() says 'hi!' -> ChildClass intercepts and says 'hello...'
$inst->protectedFunction();		// Fatal error: Call to protected method ParentClass::protectedFunction() from context '' in myExample.php on line xx
$inst->tryToAccessPrivateMethod();	// Fatal error: Call to private method ParentClass::privateFunction() from context 'ChildClass' in myExample.php on line xx

Output is in the comments.

Edited by maxxd
Link to comment
Share on other sites

You'll be able to call anything protected or public in Init() from within Router(). If you don't need to do anything different with a method in the Router() class, don't define it in the Router() class and the call will bubble up to Init() automatically. For instance:

class ParentClass{
/**
 *	Runs because the constructor is called on the child class and not intercepted.
 */
	public function __construct(){
		print("<p>This is ParentClass() calling!</p>");
	}
/**
 *	This is public and can be called from anywhere
 */
	public function doStuff(){
		print("<p>Now ParentClass() is doing stuff!</p>");
	}
/**
 *	This is protected, so can only be called from the child class. However,
 *	we're doing more with this method by adding another line of output after
 *	calling this method from the child class.
 */
	protected function polymorphismAtWork(){
		print("<p>ParentClass() says 'hi!'</p>");
	}
/**
 *	Again, this is protected and can only be called from within a child class.
 */
	protected function protectedFunction(){
		print("<p>This method is protected!</p>");
	}
/**
 *	Not even a child class can call this method.
 */
	private function privateFunction(){
		print("<p>Nope. No access, thanks</p>");
	}
}

class ChildClass extends ParentClass{
/**
 *	This is public and can be called from anywhere, yet has nothing to do with the parent class.
 */
	public function doOtherStuff(){
		print("<p>This is ChildClass() doing other stuff!</p>");
	}
/**
 *	This adds additional functionality to the parent polymorphismAtWork() method.
 *	It can completely replace the parent class method, but here we're doing some
 *	work and passing the call to the parent version for it's own output.
 */
	public function polymorphismAtWork(){
		parent::polymorphismAtWork();
		print("<p>ChildClass intercepts and says 'hello...'</p>");
	}
/**
 *	Even though the child method is public, the parent is private. This will throw an
 *	error.
 */
	public function tryToAccessPrivateMethod(){
		parent::privateFunction();
	}
}

$inst = new ChildClass();		// This is ParentClass() calling!
$inst->doStuff();			// Now ParentClass() is doing stuff!
$inst->doOtherStuff();			// This is ChildClass() doing other stuff!
$inst->polymorphismAtWork();		// ParentClass() says 'hi!' -> ChildClass intercepts and says 'hello...'
$inst->protectedFunction();		// Fatal error: Call to protected method ParentClass::protectedFunction() from context '' in myExample.php on line xx
$inst->tryToAccessPrivateMethod();	// Fatal error: Call to private method ParentClass::privateFunction() from context 'ChildClass' in myExample.php on line xx

Output is in the comments.

 

I ended up doing this, I don't know if its the right thing to do... But I can tell you that I keep exceeding the memory limit, I have tried editing the ini for more memory, but it's like it just needs more and more...

<?php

    /**
     * Created by PhpStorm.
     * User: Jamie
     * Date: 27-Jun-15
     * Time: 10:44 AM
     */

    class Init {

        private $subdir;

        public function __construct($subdir = "") {
            if($subdir != "") {
                $this->subdir = $subdir;
            }
            set_error_handler(array($this, "ErrorHandler"));
            $this->loadCore();
        }

        public function ErrorHandler($errno, $errstr, $errfile, $errline) {
            echo "<b>Custom Error:</b> [" . $errno . "] " . $errstr . "<br />";
            echo " Error on line " . $errline . " in line " . $errfile . ".";
        }

        public function logHandler() {
            $development = true;
            if($development == true) {
                error_reporting(E_ALL);
                ini_set("display_errors", "On");
            } else {
                error_reporting(E_ALL);
                ini_set("display_errors", "Off");
                ini_set("log_errors", "On");
                if (isset($this->subdirectory)) {
                    ini_set("error_log", $_SERVER["DOCUMENT_ROOT"] . DIRECTORY_SEPARATOR . $this->subdir . DIRECTORY_SEPARATOR . "Private" . DIRECTORY_SEPARATOR . "Tmp" . DIRECTORY_SEPARATOR . "Logs" . DIRECTORY_SEPARATOR . "Error.log");
                } else {
                    ini_set("error_log", $_SERVER["DOCUMENT_ROOT"] . DIRECTORY_SEPARATOR . "Private" . DIRECTORY_SEPARATOR . "Tmp" . DIRECTORY_SEPARATOR . "Logs" . DIRECTORY_SEPARATOR . "Error.log");
                }
            }
        }

        private function loadCore() {
            if($this->subdir != "") {
                if (file_exists($_SERVER["DOCUMENT_ROOT"] . DIRECTORY_SEPARATOR . $this->subdir . DIRECTORY_SEPARATOR . "Private" . DIRECTORY_SEPARATOR . "Core" . DIRECTORY_SEPARATOR . "Core.php")) {
                    require_once($_SERVER["DOCUMENT_ROOT"] . DIRECTORY_SEPARATOR . $this->subdir . DIRECTORY_SEPARATOR . "Private" . DIRECTORY_SEPARATOR . "Core" . DIRECTORY_SEPARATOR . "Core.php");
                    new Core($this->subdir);
                }
            } else {
                if (file_exists($_SERVER["DOCUMENT_ROOT"] . DIRECTORY_SEPARATOR . "Private" . DIRECTORY_SEPARATOR . "Core" . DIRECTORY_SEPARATOR . "Core.php")) {
                    require_once($_SERVER["DOCUMENT_ROOT"] . DIRECTORY_SEPARATOR . "Private" . DIRECTORY_SEPARATOR . "Core" . DIRECTORY_SEPARATOR . "Core.php");
                    new Core();
                }
            }
        }

    };

?>
<?php

    /**
     * Created by PhpStorm.
     * User: Jamie
     * Date: 29-Jun-15
     * Time: 5:42 AM
     */

    class Core {

        protected $root;
        protected $rootds;
        protected $core = array();

        public function __construct($subdir = "") {
            if($subdir != "") {
                $this->root = $_SERVER["DOCUMENT_ROOT"] . DIRECTORY_SEPARATOR . $subdir . DIRECTORY_SEPARATOR;
            } else {
                $this->root = $_SERVER["DOCUMENT_ROOT"] . DIRECTORY_SEPARATOR;
            }
            $this->rootds = DIRECTORY_SEPARATOR;
            $this->loadCoreClasses();
        }

        private function loadCoreClasses() {
            $classes = array("Request", "Redirect", "Session", "Controller", "Router");

            for($i = 0; $i < count($classes); $i++) {
                if(file_exists($this->root . "Private" . $this->rootds . "Core" . $this->rootds . $classes[$i] . ".php")) {
                    require_once($this->root . "Private" . $this->rootds . "Core" . $this->rootds . $classes[$i] . ".php");
                    if($classes[$i] != "Router" || $classes[$i] != "Controller") {
                        $this->core[$classes[$i]] = new $classes[$i];
                    }
                } else {
                    trigger_error($classes[$i] . " Class missing.");
                    exit();
                }
            }
        }

    };

?>
<?php

    /**
     * Created by PhpStorm.
     * User: Jamie
     * Date: 27-Jun-15
     * Time: 11:14 AM
     */

    class Router {

        protected $controller = "Home";
        protected $method = "index";
        protected $perams = array();

        public function __construct($init = Null) {
            $url = $this->parseURL();

            if(file_exists($_SERVER["DOCUMENT_ROOT"] . DIRECTORY_SEPARATOR . "Private" . DIRECTORY_SEPARATOR . "Controllers" . DIRECTORY_SEPARATOR . $url[0] . ".php")) {
                $this->controller = $url[0];
                unset($url[0]);
            }
            require_once($_SERVER["DOCUMENT_ROOT"] . DIRECTORY_SEPARATOR . "Private" . DIRECTORY_SEPARATOR . "Controllers" . DIRECTORY_SEPARATOR . $this->controller . ".php");
            $this->controller = new $this->controller;

            if(isset($url[1])) {
                if(method_exists($this->controller, $url[1])) {
                    $this->method = $url[1];
                    unset($url[1]);
                }
            }

            $this->perams = $url ? array_values($url) : array();
            call_user_func_array(array($this->controller, $this->method), $this->perams);
        }

        private function parseURL() {
            if(isset($_GET["url"])) {
                return explode("/", filter_var(rtrim($_GET["url"], "/"), FILTER_SANITIZE_URL));
            }
        }

    };

?>
Link to comment
Share on other sites

While you're still in the design stage

 

I don't agree with the idea of a discreet design "stage". Designs should evolve over time and can be refactored. I never stick to a plan and I consider it a good practice to not plan too far ahead.

Link to comment
Share on other sites

I don't agree with the idea of a discreet design "stage". Designs should evolve over time and can be refactored. I never stick to a plan and I consider it a good practice to not plan too far ahead.

Writing code should be the last part of the process. You need a good idea of what your application is going to do before you start writing it. You can avoid lots of refactoring if you know where you're going to start with.

Link to comment
Share on other sites

Writing code should be the last part of the process. You need a good idea of what your application is going to do before you start writing it. You can avoid lots of refactoring if you know where you're going to start with.

No, refactoring should happen constantly, all the time. You should not design a big plan up front, because the plan will inevitably be wrong - if the plan is not perfect it causes all kinds of issues. What happens if you think of a better way during development? Do you just stick to your plan even though you can see the advantage to doing something a better way?

 

The truth is there shouldn't really be too many discrete stages. There certainly shouldn't be a design, code, test phase - these should all happen interchangeably and be combined.

 

I use TDD, which means that I get to refactor my code without the fear of change. This means I can start with only a minimal design (I usually have an idea in mind, but never stick to it religiously and I never design too much in advance) and I can incrementally create a great design by constantly refactoring using feedback from my tests. This is essentially a form of "evidence based design", which relies on short feedback loops that lead to constant incremental improvements. 

 

I would never trust an upfront design. There's nothing wrong with jotting some ideas down and aiming for a certain design, but when the feedback you get from your tests (and you DO have automated tests, don't you?) tells you a design isn't working, you should adapt to that feedback and change your design now, not later.

 

Refactoring is something that you do while you code - it's not something you do at the end, and you should be writing code AS you're designing and fleshing out your ideas.

Link to comment
Share on other sites

TDD basically implies that you're coding to a design. You design what the app should do, write tests, then write code.

 

Yes, refactoring is important and a regular part of development. But you should still have a pretty good general idea of what you're building.

Link to comment
Share on other sites

TDD basically implies that you're coding to a design. You design what the app should do, write tests, then write code.

 

Yes, refactoring is important and a regular part of development. But you should still have a pretty good general idea of what you're building.

 

TDD means nothing of the sort. Test DRIVEN DESIGN. The tests are all based on business behaviour, not implementation details (so nothing, or as little as possible, about the structure of the code should be baked into the tests), and the tests are not all written at once and then made to pass with the "coding" step. You write one test. You see it fail. You make it pass and then you refactor if necessary, then you write another test. Repeat until you're done.

 

The refactoring stage, which is a natural and essential part of the TDD process, is where you make important design decisions. You may split out an object into smaller objects, extract functions, move things up and down a hierarchy, split out new objects and so on and so forth. This is part of the process in tdd:

 

1) Write a failing test

2) Make the test pass

3) Refactor if necessary

4) Repeat until done

 

So TDD is all about creating a design based on evidence, not following a blue print. You become much more intimately familiar with the code and the solution domain while you are working on it, so any design process that allows you to use that evidence to inform the architectural design of your code is a good thing, no?

Link to comment
Share on other sites

TDD means Test Driven Development.

 

Like I said, refactoring is a vital part of development. I'm not arguing there. But that doesn't mean you need to unnecessarily spend hours refactoring when you could have just given a bit of thought to how you build it first.

 

How do you estimate your workload if you have no idea what you're doing before you start? How do you break workload up between team members if nobody knows how it will be built?

 

I find it very beneficial to just grab a notebook and sketch some stuff out before I start. Sometimes I can flush out bad ideas before I waste the time coding them, only to discover they won't work. Or, maybe something is complex and it's just easier to visualize it on paper to prevent insanity.

 

Writing code takes time. There's no point in spending a bunch of time writing code that is inherently flawed.

Link to comment
Share on other sites

TDD means Test Driven Development.

 

Like I said, refactoring is a vital part of development. I'm not arguing there. But that doesn't mean you need to unnecessarily spend hours refactoring when you could have just given a bit of thought to how you build it first.

 

How do you estimate your workload if you have no idea what you're doing before you start? How do you break workload up between team members if nobody knows how it will be built?

 

I find it very beneficial to just grab a notebook and sketch some stuff out before I start. Sometimes I can flush out bad ideas before I waste the time coding them, only to discover they won't work. Or, maybe something is complex and it's just easier to visualize it on paper to prevent insanity.

 

Writing code takes time. There's no point in spending a bunch of time writing code that is inherently flawed.

 

Test driven design is a better name for what it's really all about: http://www.drdobbs.com/architecture-and-design/test-driven-design/240168102

 

 But that doesn't mean you need to unnecessarily spend hours refactoring when you could have just given a bit of thought to how you build it first.

 

 

 

Most refactoring steps are actually quite small. The idea is that it's hard to do two things at once - getting the actual logic and functionality right is hard enough - doing it in a neat way is even harder. So focus on getting the functionality right first, write tests that don't care about the implementation (in so far as this is possible), and then, once you've got the tests green, refactor. Because refactoring is done regularly, most refactorings are quite small and fast. It can be removing some code duplication here, renaming a few variables, extracting a method there and so on. Sometimes the refactoring step takes a minute or so and nothing more. Other times it can take a bit longer, but it's usually the fastest part of the whole process. I've heard it described with an analogy to how chefs work - if you tidy up as you go along you keep the kitchen clean and it's easy to keep making more meals. Otherwise the kitchen gets dirty - same with code - you end up with technical debt if you don't clean up after yourself. So do it often and early and you only end up tidying up small bits here and there instead of spending ages with it.

 

How do you estimate your workload if you have no idea what you're doing before you start? How do you break workload up between team members if nobody knows how it will be built?

 

 

 

Well, firstly we never estimate to dates. We try to break work up into quite small amounts and our features are generally quite small and focused. We work in feature squads, so there's usually only one or two developers working on a feature at any one point in time.

 

Instead of estimating to dates, we use story points and we're quite flexible about changing these along the way. The fact is, having dates set up front usually doesn't work any way - it just gives project managers false hope and often ends up with people rushing to meet deadlines and thereby creating more technical debt, which just compounds itself. It often ends up in a finger pointing exercise in my experience.

 

The way we work obviously involves a lot of communication and team work. We also accept that estimation is not a science and shouldn't be treated as such. Keeping the quality of the code high is a priority, so just having something functionally complete doesn't mean it means our definition of "done". All code is hosted privately on Github and has to be code reviewed before getting merged into master.

 

I find it very beneficial to just grab a notebook and sketch some stuff out before I start. Sometimes I can flush out bad ideas before I waste the time coding them, only to discover they won't work. Or, maybe something is complex and it's just easier to visualize it on paper to prevent insanity.

 

 

I agree with you completely. All I'm saying is I don't stick to a plan religiously and I'm always happy to move stuff around and adapt the plan if needs be. I also don't need to know every last detail before I start coding. I sketch stuff down, sure. Sometimes I think I may know which design patterns I'm going to use and so on and so forth, but I always work test first in the way I described above, and I listen to the feedback my tests are giving me. If my tests are telling me my design is bad, I change it. If they're telling me the design looks good, I carry on down that path. Sometimes I don't know how I'm going to do something and I simply make the tests pass then work out the design in the refactoring stage.

 

>Writing code takes time. There's no point in spending a bunch of time writing code that is inherently flawed. 

 

 

 
That's why I use TDD. Because I want to write clean code that I've got high confidence in.
 
 
From the article:
 
To my mind, TDD (and its more-refined cousins BDD and ATDD) are not testing methodologies at all. They're design methodologies. In fact, let's just call it Test-Driven Design to eliminate the confusion.

 

Edited by citypaul
Link to comment
Share on other sites

Most refactoring steps are actually quite small. The idea is that it's hard to do two things at once - getting the actual logic and functionality right is hard enough - doing it in a neat way is even harder. So focus on getting the functionality right first, write tests that don't care about the implementation (in so far as this is possible), and then, once you've got the tests green, refactor. Because refactoring is done regularly, most refactorings are quite small and fast. It can be removing some code duplication here, renaming a few variables, extracting a method there and so on. Sometimes the refactoring step takes a minute or so and nothing more. Other times it can take a bit longer, but it's usually the fastest part of the whole process. I've heard it described with an analogy to how chefs work - if you tidy up as you go along you keep the kitchen clean and it's easy to keep making more meals. Otherwise the kitchen gets dirty - same with code - you end up with technical debt if you don't clean up after yourself. So do it often and early and you only end up tidying up small bits here and there instead of spending ages with it.

I think we're arguing about different things. Refactoring as you have laid out above is absolutely okay. As you've pointed out, that is the natural process in TDD. It can't be eliminated.

 

What I'm talking about is large scale refactors for something that you thought might work but ended up not. It's easy to make broad assumptions and not realize something stinks until you get to the point that you need it. You might waste a few hours before you hit that point, and then have to refactor a bunch of stuff.

 

If I'm building anything that will consist of more than a couple classes, I like to just sit and jot down what it will look like as a general overview. Write some classes down, some methods that I know I'll need, any dependencies that I think I'll need, how I will get those dependencies in, etc. There is no specifics, and it's generally all very pseudo-codey, but I have something to run with and refer to.

 

EDIT: Anyway, these are just my opinions. Your mileage may vary. I think we're pretty far off topic at this point...

Edited by scootstah
Link to comment
Share on other sites

If you're running out of memory, you probably have an infinite loop or circular reference or something somewhere. That can be difficult to track down without proper tooling.

 

I did check, can't find anything...

 

 

And please, I have a general idea in my head... Which I'm trying to implement with TDD, don't necessarily need to design as I'm using MVC, which is a "design" pattern, I need to implement that first then somewhat design the rest when I have the MVC in place. No need to argue the point.

Edited by jbonnett
Link to comment
Share on other sites

If you can't find anything obvious in your code, you should try using a profiler like Xdebug. Most decent IDE's will support Xdebug. You can use Xdebug to profile your application and determine exactly which functions are using lots of memory. This should help you pin down your memory leak.

Link to comment
Share on other sites

If you can't find anything obvious in your code, you should try using a profiler like Xdebug. Most decent IDE's will support Xdebug. You can use Xdebug to profile your application and determine exactly which functions are using lots of memory. This should help you pin down your memory leak.

 

Already tried, not showing nothing... I can tell you that it's with the core class specifically the constructor, it's almost like the constructor is running twice or the if statement inside the constructor is true both sides of the condition... Note I'm only calling the class once.

public function __construct($subdir = "") {
            if($subdir != "") {
                $this->root = $_SERVER["DOCUMENT_ROOT"] . DIRECTORY_SEPARATOR . $subdir . DIRECTORY_SEPARATOR;
            } else {
                $this->root = $_SERVER["DOCUMENT_ROOT"] . DIRECTORY_SEPARATOR;
            }
			echo $this->root . "<br/>";
            $this->rootds = DIRECTORY_SEPARATOR;
            $this->loadCoreClasses();
        }
Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.