Tinker all the things

You have no real friends, unless...

Posted by lagbox on May 18, 2016 artisan cli laravel

Tinker all the things

Artisan tinker is the interactive shell that comes with your Laravel application; php artisan tinker and you are there. This is a great tool for learning about what objects you are dealing with, testing some quick snippets or general expirimentation.

Interact with your application

If you don't know artisan tinker you have no real friends.

⚡ artisan tinker
Psy Shell v0.7.0 (PHP 7.0.4-7+deb.sury.org~wily+2 — cli) by Justin Hileman
>>>

But lagbox, what can I do with this.

>>> $u = App\User::first();
=> App\User {#768
 id: "1",
 name: "admin",
 email: "admin@admin",
 ...
}
>>> $u->name;
=> "admin"
>>>

Simple enough. How about a real example? Lets say you forgot your password while in development and dont want to deal with emails. Lets just change it now.

>>> $u->password = bcrypt('correcthorsebatterystaple');
=> "$2z$40$l2U8PyCVbeKfV1y3L9rftO8ZI9Ap9WXepRgzHrsT2stHlJpe41AKY"
>>> $u->save();
=> true
>>>

What is the method signature for array_only and what does the function look like?

>>> show array_only
  > 212|     function array_only($array, $keys)
    213|     {
    214|         return Arr::only($array, $keys);
    215|     }

Oh yes, it is a helper for the Arr helper object. Well what does that look like?

>>> show Illuminate\Support\Arr::only
  > 325|     public static function only($array, $keys)
    326|     {
    327|         return array_intersect_key($array, array_flip((array) $keys));
    328|     }

>>>

In 5.2.22 can array_only take a Eloquent Model which implements array access?

>>> array_only($u, ['name', 'email']);
PHP warning:  array_intersect_key(): Argument #1 is not an array in /var/www/ask/vendor/laravel/framework/src/Illuminate/Support/Arr.php on line 327
>>>

Apparently not.

What type of object does that relation method return at runtime?

>>> $v = App\Video::first();
=> App\Video {#812
     id: 1,
     band_id: 1,
     created_at: "2016-05-10 20:33:52",
     updated_at: "2016-05-10 20:36:13",
   }
>>> $v->band();
=> Illuminate\Database\Eloquent\Relations\BelongsTo {#731}
>>>

Or we could also take a direct look at that method

>>> show $v->band
  > 13|     public function band()
    14|     {
    15|         return $this->belongsTo(Band::class);
    16|     }

Is null really false (truthy)?

>>> null == false
=> true
>>>

Why yes it is. But it isn't actually false, right?

>>> null === false
=> false
>>>

Everything is right in the world.

Pause for a Psy

PsySH's site

"A runtime developer console, interactive debugger and REPL for PHP."

Tinker since 5.0 has an upgraded REPL (Read-Eval-Print-Loop) that it uses, PsySH. This is a very powerful tool by itself. It is worth the time to take a look into psy and what it offers.

The kicker, it can be used as a debugger, bang.

Documentation

Inline documentation is ... kinda sweet.

>>> doc array_only
function array_only($array, $keys)

Description:
  Get a subset of the items from the given array.

Param:
  array         $array
  array|string  $keys

Return:
  array
>>>

How about on an object? (Read documentation in context)

>>> $user = App\User::first();
=> App\User {#724
     id: 1,
     name: "admin",
     email: "admin@admin",
     admin: 1,
     created_at: "2016-05-08 05:11:52",
     updated_at: "2016-05-17 04:26:13",
   }
>>> doc $user->__get
public function __get($key)

Description:
  Dynamically retrieve attributes on the model.

Param:
  string  $key

Return:
  mixed
>>>

From one of the above examples of what is returned from our Video model's band method. We know it returns $this->belongsTo(Band::class). But what does that return?

>>> doc $v->belongsTo
public function belongsTo($related, $foreignKey = null, $otherKey = null, $relat

Description:
  Define an inverse one-to-one or many relationship.

Param:
  string  $related
  string  $foreignKey
  string  $otherKey
  string  $relation

Return:
  \Illuminate\Database\Eloquent\Relations\BelongsTo

PHP docs for psy

Do yourself a favor and download the PHP documentation needed to have access to the built in PHP objects and functions.

Downloading the Manual

>>> doc array_diff
function array_diff($arr1, $arrays)

Description:
  Computes the difference of arrays

  Compares $array1 against one or more other arrays and returns the values in $a
  present in any of the other arrays.

Param:
  array  $array1  The array to compare from
  array  $array2  An array to compare against
  array  $...     More arrays to compare against

Return:
  array  Returns an array containing all the entries from $array1 that are not p
         other arrays.

See Also:
   * array_diff_assoc()
   * array_intersect()
   * array_intersect_assoc()

(END)

Helpy helpers

You have seen a bunch of helper commands already but there are some more helpful things psy has to offer.

Oh that more complex thing I just did that I forgot to assign to a variable, I could hit up and rerun it, or ...

>>> $blah = $_
// $_ result of the last successful statement

What was the last exception? I have forgotten.

>>> $_e

wtf mate?

wtf ... Yes really, there is a wtf command in psy.

Shows a few lines of the backtrace of the most recent exception. If you want to see more lines, add more question marks or exclamation marks:

 e.g.
 >>> wtf ?
 >>> wtf ?!???!?!?

ls -al ... all the things

Everyone's favorite shell command ls (list). Again, yes there really is this command is psy.

List variables, constants, classes, interfaces, traits, functions, methods, and properties. Called without options, this will return a list of variables currently in scope

>>> ls -l App\User

Class Constants:
  CREATED_AT   "created_at"
  UPDATED_AT   "updated_at"

Class Properties:
  $exists
  $incrementing
  $manyMethods
  $snakeAttributes
  $timestamps
  $wasRecentlyCreated

Class Methods:
  __call                       public function __call($method, $parameters)
  __callStatic                 public static function __callStatic($method, $par
  __construct                  public function __construct(array $attributes = n
  __get                        public function __get($key)
  __isset                      public function __isset($key)
  __set                        public function __set($key, $value)
  __toString                   public function __toString()
  __unset                      public function __unset($key)
  ...

Round it up tinkerers

You may not want to always add a test route closure with random things in it to test things inside your application. You will be able to do what you can in your application in tinker. Fire events, dispatch jobs, dispatch routes, do what you would like.

I find using tinker to be the fastest method to quickly test something or figure out how things work. There really is no reason to have to hit a route with your browser to test something simple or random when you have an interactive shell like this.