Since you want to process in perl, I'm inferring that you don't want the non-data-like objects within a model. We can filter out the components we don't want and write that to json.
Using the first example from ?coxph:
library(survival)
test1 <- list(time=c(4,3,1,1,2,2,3), 
              status=c(1,1,1,0,1,1,0), 
              x=c(0,2,1,1,1,0,0), 
              sex=c(0,0,0,0,1,1,1)) 
mdl <- coxph(Surv(time, status) ~ x + strata(sex), test1) 
We can see what each of the components of mdl are:
str(lapply(mdl, class))
# List of 20
#  $ coefficients     : chr "numeric"
#  $ var              : chr [1:2] "matrix" "array"
#  $ loglik           : chr "numeric"
#  $ score            : chr "numeric"
#  $ iter             : chr "integer"
#  $ linear.predictors: chr "numeric"
#  $ residuals        : chr "numeric"
#  $ means            : chr "numeric"
#  $ method           : chr "character"
#  $ n                : chr "integer"
#  $ nevent           : chr "numeric"
#  $ terms            : chr [1:2] "terms" "formula"
#  $ assign           : chr "list"
#  $ wald.test        : chr "numeric"
#  $ concordance      : chr "numeric"
#  $ y                : chr "Surv"
#  $ timefix          : chr "logical"
#  $ formula          : chr "formula"
#  $ xlevels          : chr "list"
#  $ call             : chr "call"
It should be clear that we don't want things like formula and call, we can just accept the others:
jsonlite::toJSON(Filter(function(z) !inherits(z, c("formula", "call")), mdl))
# Error: No method asJSON S3 class: Surv
Okay, that's one you might (?) want to keep that we will need to reclass:
mdl$y
#  1  2  3  4  5  6  7 
#  4  3  1 1+  2  2 3+ 
dput(mdl$y)
# structure(c(4, 3, 1, 1, 2, 2, 3, 1, 1, 1, 0, 1, 1, 0), .Dim = c(7L, 
# 2L), .Dimnames = list(c("1", "2", "3", "4", "5", "6", "7"), c("time", 
# "status")), type = "right", class = "Surv")
That looks like a matrix to me ...
as.matrix(mdl$y)
#   time status
# 1    4      1
# 2    3      1
# 3    1      1
# 4    1      0
# 5    2      1
# 6    2      1
# 7    3      0
mdl$y <- as.matrix(mdl$y)
jsonlite::toJSON(Filter(function(z) !inherits(z, c("formula", "call")), mdl))
# {"coefficients":[0.8023],"var":[[0.6763]],"loglik":[-3.8712,-3.3277],"score":[1.0509],"iter":[4],"linear.predictors":[-0.5731,1.0316,0.2292,0.2292,0.2292,-0.5731,-0.5731],"residuals":[-0.2631,-0.3094,0.7863,-0.2137,0.0463,0.5725,-0.6187],"means":[0.7143],"method":["efron"],"n":[7],"nevent":[5],"assign":{"x":[1]},"wald.test":[0.9518],"concordance":[3,1,2,1,0,0.6667,0.1667],"y":[[4,1],[3,1],[1,1],[1,0],[2,1],[2,1],[3,0]],"timefix":[true],"xlevels":{"strata(sex)":["sex=0","sex=1"]}} 
Note that mdl$y loses its names. If you want to preserve the column names of the matrix, convert to a frame instead:
mdl$y <- data.frame(as.matrix(mdl$y))
jsonlite::toJSON(Filter(function(z) !inherits(z, c("formula", "call")), mdl))
# {"coefficients":[0.8023],"var":[[0.6763]],"loglik":[-3.8712,-3.3277],"score":[1.0509],"iter":[4],"linear.predictors":[-0.5731,1.0316,0.2292,0.2292,0.2292,-0.5731,-0.5731],"residuals":[-0.2631,-0.3094,0.7863,-0.2137,0.0463,0.5725,-0.6187],"means":[0.7143],"method":["efron"],"n":[7],"nevent":[5],"assign":{"x":[1]},"wald.test":[0.9518],"concordance":[3,1,2,1,0,0.6667,0.1667],"y":[{"time":4,"status":1},{"time":3,"status":1},{"time":1,"status":1},{"time":1,"status":0},{"time":2,"status":1},{"time":2,"status":1},{"time":3,"status":0}],"timefix":[true],"xlevels":{"strata(sex)":["sex=0","sex=1"]}} 
For archiving reasons, if you want to preserve the formula as a string, you can do that with one of the following (and then toJSON).
## this
txt <- as.character(mdl$formula)
txt <- paste(c(txt[2], txt[-2]), collapse = " ")
mdl$formula <- txt
## or this, `paste`ing in case of multiline formulas
mdl$formula <- paste(capture.output(print(mdl$formula)), collapse = " ")