ClanCats Logo


Container File Syntax

Container files are written in a very simple meta language.


The language supports the following scalar types:

  • Strings Single and double quoted.
    'hello' & "world"
  • Numbers float / double, int.
    3.14, 42
  • Booleans
    true and false.
  • Null
  • Arrays list and associative.
    {'A', 'B', 'C'}, {'A': 10, 'B': 20}


Container files do not differentiate between different number types because it would be an unnecessary overhead, we forward that job directly to PHP.

42 # Int
42.01 # Float
-42.12345678912345 # Double

That means that also the floating point precision is handled by PHP. All values are interpreted means large doubles might be stored rounded.


Strings must always be encapsulated with a single ' or double " quote. This serves mainly a comfort purpose when having many quotes inside your string not having to escape them all.

Escaping of special characters works just the usual way.

:say: 'Hello it\'s me!'`

Beloved or Hated emojis will also work just fine.

:snails: '🐌🐌🐌'

Booleans and Null

There is not much to say about them:

:nothing: null
:positive: true
:negative: false


It's important to notice that all arrays are internally associative. When defining a simple list the associative key is automatically generated and represents the index of the item.

This means that the array {'A', 'B'} equals {0: 'A', 1: 'B'}.

Arrays can be defined multidimensional:

    'title': 'Some catchy title with Star Wars',
    'tags': {'top10', 'movies', 'space'},
    'body': 'Lorem ipsum ...',
            'text': 'Awesome!',
            'by': 'Some Dude',


Parameters or configuration values can also be defined inside the container files.

A parameter is always prefixed with a : character.

:database.hostname: ""
:database.port: 7878
:database.cache: true

Service Definition

A service definition is always named and must be prefixed with a @ character.

# <service name>: <class name>
@log.adapter: FileAdapter

The class name can contain the full namespace.

@log.adapter: Acme\Log\FileAdapter


Constructor arguments can be passed after the class name.

@dude: Person("Jeffery Lebowski")

Referenced arguments

Arguments can reference a parameter or service.

:name: 'Jeffery Lebowski'

@dude: Person(:name)
@mysql: MySQLAdapter('localhost', 'root', '')

@repository.posts: Repositories/Post(@mysql)

Method calls

Method calls can be assigned to a service definition.

@jones: Person('Duncan Jones')
@sam: Person('Sam Rockwell')

@movie.moon: Movie('Moon')
  - setDirector(@jones)
  - addCast(@sam)
  - setTags({'Sci-fi', 'Space'})

Service metadata

Metadata can be assigned to every service definition.

Its then possible to fetch the services matching a metadata key.

@controller.auth.sign_in: Controller\Auth\SignInController(@auth)
  = route: {'GET', 'POST'}, '/signin'

The metadata key is always a vector / array so you can add multiple of the same type:

@controller.auth.sign_in: Controller\Auth\SignInController(@auth)
  = route: {'GET', 'POST'}, '/signin'
  = tag: 'users'
  = tag: 'auth'

The elements inside the metadata definition can have named keys:

@app.bootstrap: Bootstrap()
  = on: 'app.start' call: 'onAppStart'

Service Updates

It is possible to update already defined services with more construction calls and metadata. This is quite handy to organize large amount of dependencies with a dynamic lookups.

You could for example define your logger in one file.

@logger.main: Acme\Logger

And add observers using a construction call where you need them.

@logger.observers.email_devs: Acme\EmailLogObserver('[email protected]')
@logger.observers.email_support: Acme\EmailLogObserver('[email protected]')

  - addObserver(@logger.observers.email_devs)
  - addObserver(@logger.observers.email_support)


Other container files can be imported from the container namespace.

import config
import app/dashboard
import app/user
import app/shop


Services and Parameters have been explicit overwritten if they have already been defined.

:ship: 'Star Destroyer'

override :ship: 'X-Wing'