Learn from your fellow PHP developers with our PHP blogs, or help share the knowledge you've gained by writing your own.
$users = [new User(), new User()];
I see a lost opportunity to use Iterator.public function getUsers(): array
{
return $userArray;
}
public function setUsersToActiveState()
{
$users = $this->getUsers();
foreach ($users as $user) {
if(!$user->getActiveStatus()) {
$user->setActiveStatus(true);
}
}
}
There immediately two problems occurred.
class UsersCollection implements \IteratorAggregate
{
private $users = [];
public function getIterator() : UserIterator
{
return new UserIterator($this);
}
public function getUser($position)
{
if (isset($this->users[$position])) {
return $this->users[$position];
}
return null;
}
public function count() : int
{
return count($this->users);
}
public function addUser(User $users)
{
$this->users[] = $users;
}
}
class UserIterator implements \Iterator
{
private $position = 0;
private $userCollection;
public function __construct(UsersCollection $userCollection)
{
$this->userCollection = $userCollection;
}
public function current() : User
{
return $this->userCollection->getUser($this->position);
}
public function next()
{
$this->position++;
}
public function key() : int
{
return $this->position;
}
public function valid() : bool
{
return !is_null($this->userCollection->getUser($this->position));
}
public function rewind()
{
$this->position = 0;
}
}
class UsersCollectionTest extends TestCase
{
public function testUsersCollectionShouldReturnNullForNotExistingUserPosition()
{
$usersCollection = new UsersCollection();
$this->assertEquals(null, $usersCollection->getUser(1));
}
public function testEmptyUsersCollection()
{
$usersCollection = new UsersCollection();
$this->assertEquals(new UserIterator($usersCollection), $usersCollection->getIterator());
$this->assertEquals(0, $usersCollection->count());
}
public function testUsersCollectionWithUserElements()
{
$usersCollection = new UsersCollection();
$usersCollection->addUser($this->getUserMock());
$usersCollection->addUser($this->getUserMock());
$this->assertEquals(new UserIterator($usersCollection), $usersCollection->getIterator());
$this->assertEquals($this->getUserMock(), $usersCollection->getUser(1));
$this->assertEquals(2, $usersCollection->count());
}
private function getUserMock()
{
}
}
class UserIteratorTest extends MockClass
{
public function testCurrent()
{
$iterator = $this->getIterator();
$current = $iterator->current();
$this->assertEquals($this->getUserMock(), $current);
}
public function testNext()
{
$iterator = $this->getIterator();
$iterator->next();
$this->assertEquals(1, $iterator->key());
}
public function testKey()
{
$iterator = $this->getIterator();
$iterator->next();
$iterator->next();
$this->assertEquals(2, $iterator->key());
}
public function testValidIfItemInvalid()
{
$iterator = $this->getIterator();
$iterator->next();
$iterator->next();
$iterator->next();
$this->assertEquals(false, $iterator->valid());
}
public function testValidIfItemIsValid()
{
$iterator = $this->getIterator();
$iterator->next();
$this->assertEquals(true, $iterator->valid());
}
public function testRewind()
{
$iterator = $this->getIterator();
$iterator->rewind();
$this->assertEquals(0, $iterator->key());
}
private function getIterator() : UserIterator
{
return new UserIterator($this->getCollection());
}
private function getCollection() : UsersCollection
{
$userItems[] = $this->getUserMock();
$userItems[] = $this->getUserMock();
$usersCollection = new UsersCollection();
foreach ($userItems as $user) {
$usersCollection->addUser($user);
}
return $usersCollection;
}
private function getUserMock()
{
}
}
public function getUsers(): UsersCollection
{
$userCollection = new UsersCollection();
foreach ($whatIGetFromDatabase as $user) {
$userCollection->addUser($user);
}
return $userCollection;
}
public fucntion setUsersToActiveState()
{
$users = $this->getUsers();
foreach ($users as $user) {
if(!$user->getActiveStatus()) {
$user->setActiveStatus(true);
}
}
}
As you can see setUsersToActiveState remains the same, we only do not need to specify for our IDE or collagues what type $users variable is. public function addUser(User $users)
{
if ($user->getAge() > 18) {
$this->users[] = $users;
}
}
public function addUsers(array $users)
{
foreach($users as $user) {
$this->addUser(User $users);
}
}
var_dump()
, which is obviously not the best way to do it. If you see the code for the first time, if you work with legacy code - step-by-step interactive debugging is the way to go. Sometimes it can save you hours of old school var_dumping.watch phpunit /path/to/test
while developing: this way the test is run every 2 seconds, you switch to the terminal whenever you want to see the latest results and that's it. However, there are certain advantages in running tests from the IDE. First, it's super-handy to launch a test method, test class or a whole folder with tests, just by pressing a hotkey. Second, the test results appear right there, in PHPStorm, with failures and their stack traces, every entry clickable and takes you directly to the file:line where a nasty thing happened. I also find the ability to run a debugger for a unit test, extremely attractive. Test fails, you click on a trace entry, get to a problematic line, place a break point, re-run the test in debug mode - and there you go.$HOME/projects/cool-project
, but inside a docker or on a remote host it might be located at /app
or /var/www
, then you have to let PHPStorm know about this.Debugging is like being the detective in a crime movie where you are also the murderer. Filipe Fortes a.k.a. @fortes
$cache = app("cache");
app("cache"")
and expect a Cache\Repository
instance as result. If I pass the result of this call to a function that requires a Cache\Repository
as parameter, I will probably have a code inspection warning from IDE. Moreover, if I want proper autocompletion, I will have to add additional comment:
$cache = app("cache");
namespace App;
class MyApp extends Application
{
public function cacheRepository(): Repository
{
return $this->make(Repository::class);
}
}
TypeError
in case of a misconfiguration, and I have a type-hint which allows the IDE to recognize the return value. Bye-bye nasty comment lines and IDE warnings! I make a method per service, with type-hints, like dbConnection()
or viewFactory()
- works really well for me!bootstrap/app.php
, should reside in that custom class:namespace App;
class MyApp extends Application
{
public function __construct()
{
define('LARAVEL_START', microtime(true));
define("APP_ROOT", realpath(__DIR__ . "/../"));
parent::__construct(APP_ROOT);
$this->setUp();
}
private function setUp()
{
$this->singleton(
Contracts\Http\Kernel::class,
\App\Http\Kernel::class
);
}
}
bootstrap/app.php
becomes just this:return new \App\MyApp;
app()
function will also return an instance of MyApp from now on. However, it's @phpdoc says it returns \Illuminate\Foundation\Application
, so for better clarity, I also added my own accessor method:namespace App;
class MyApp extends Application
{
public static function app(): self
{
$ret = parent::getInstance();
return $ret;
}
}
MyApp::app()
. The IDE wil be aware of the return type due to the type-hint, so I get everything I want for clean and clear development.Zephir, an open source, high-level language designed to ease the creation and
$variables
. You only can create object oriented extensions, and all the classes written in Zephir must be namespaced. A different and stricter type system exists in Zephir, which allows for transpiling the code you write, into a real C extension.I finally joined NomadPHP because in the current climate, I feel like I need to give back to the community, and share some of the things that I've learned over the years.